From 5b5d11eab13a4f7054e187f6621f2e129602d3f9 Mon Sep 17 00:00:00 2001 From: sthoene Date: Fri, 1 Aug 2025 15:31:48 +0200 Subject: [PATCH 01/52] refactor BaseSensorClass --- src/ansys/speos/core/generic/constants.py | 38 ++++ src/ansys/speos/core/sensor.py | 236 +++++++++++++++------- 2 files changed, 199 insertions(+), 75 deletions(-) diff --git a/src/ansys/speos/core/generic/constants.py b/src/ansys/speos/core/generic/constants.py index bea4e940c..4cca3ff33 100644 --- a/src/ansys/speos/core/generic/constants.py +++ b/src/ansys/speos/core/generic/constants.py @@ -38,3 +38,41 @@ """Maximum message Size accepted by grpc channel, By default, 4194304. """ + + +class SENSOR: + """Constant class for Sensors.""" + + class WAVELENGTHSRANGE: + """Wavelength constants.""" + + START = 400 + """Wavelength start value.""" + END = 700 + """Wavelength end value.""" + SAMPLING = 13 + """Wavelength sampling.""" + + class DIMENSIONS: + """Dimension Constants.""" + + X_START = -50 + """Lower bound x axis.""" + X_END = 50 + """Upper bound x axis.""" + X_SAMPLING = 100 + """Sampling x axis.""" + Y_START = -50 + """Lower bound y axis.""" + Y_END = 50 + """Upper bound y axis.""" + Y_SAMPLING = 100 + """Sampling y axis.""" + + class LAYERTYPES: + """Layer Separation constants.""" + + MAXIMUM_NB_OF_SEQUENCE = 10 + """Number of sequences stored in sensor.""" + INCIDENCE_SAMPLING = 9 + """Number of incidence sampling stored in sensor""" diff --git a/src/ansys/speos/core/sensor.py b/src/ansys/speos/core/sensor.py index ae122bfd6..d24e1ac25 100644 --- a/src/ansys/speos/core/sensor.py +++ b/src/ansys/speos/core/sensor.py @@ -34,6 +34,7 @@ from ansys.api.speos.sensor.v1 import camera_sensor_pb2, common_pb2, sensor_pb2 import ansys.speos.core as core +from ansys.speos.core.generic.constants import SENSOR import ansys.speos.core.generic.general_methods as general_methods from ansys.speos.core.generic.visualization_methods import _VisualData, local2absolute from ansys.speos.core.geo_ref import GeoRef @@ -160,49 +161,68 @@ def __init__( if default_values: # Default values - self.set_start().set_end().set_sampling() + self.start = SENSOR.WAVELENGTHSRANGE.START + self.end = SENSOR.WAVELENGTHSRANGE.END + self.sampling = SENSOR.WAVELENGTHSRANGE.SAMPLING - def set_start(self, value: float = 400) -> BaseSensor.WavelengthsRange: + @property + def start(self) -> float: + """The minimum wavelength of the range.""" + if isinstance(self._wavelengths_range, common_pb2.WavelengthsRange): + return self._wavelengths_range.w_start + else: + return self._wavelengths_range.wavelength_start + + @start.setter + def start(self, value: float): """Set the minimum wavelength of the range. Parameters ---------- value : float Minimum wavelength (nm). - By default, ``400``. - - Returns - ------- - ansys.speos.core.sensor.BaseSensor.WavelengthsRange - WavelengthsRange. """ if isinstance(self._wavelengths_range, common_pb2.WavelengthsRange): self._wavelengths_range.w_start = value else: self._wavelengths_range.wavelength_start = value - return self - def set_end(self, value: float = 700) -> BaseSensor.WavelengthsRange: + @property + def end(self) -> float: + """Set the maximum wavelength of the range. + + By default, ``700``. + """ + if isinstance(self._wavelengths_range, common_pb2.WavelengthsRange): + return self._wavelengths_range.w_end + else: + return self._wavelengths_range.wavelength_end + + @end.setter + def end(self, value: float): """Set the maximum wavelength of the range. Parameters ---------- value : float Maximum wavelength (nm). - By default, ``700``. - - Returns - ------- - ansys.speos.core.sensor.BaseSensor.WavelengthsRange - WavelengthsRange. """ if isinstance(self._wavelengths_range, common_pb2.WavelengthsRange): self._wavelengths_range.w_end = value else: self._wavelengths_range.wavelength_end = value - return self - def set_sampling(self, value: int = 13) -> BaseSensor.WavelengthsRange: + @property + def sampling(self) -> int: + """Set the sampling of wavelengths range. + + By default, ``13``. + """ + if isinstance(self._wavelengths_range, common_pb2.WavelengthsRange): + return self._wavelengths_range.w_sampling + + @sampling.setter + def sampling(self, value: int = 13): """Set the sampling of wavelengths range. Parameters @@ -210,16 +230,9 @@ def set_sampling(self, value: int = 13) -> BaseSensor.WavelengthsRange: value : int Number of wavelengths to be taken into account between the minimum and maximum wavelengths range. - By default, ``13``. - - Returns - ------- - ansys.speos.core.sensor.BaseSensor.WavelengthsRange - WavelengthsRange. """ if isinstance(self._wavelengths_range, common_pb2.WavelengthsRange): self._wavelengths_range.w_sampling = value - return self class Dimensions: """Dimensions of the sensor. @@ -254,109 +267,156 @@ def __init__( if default_values: # Default values - self.set_x_start().set_x_end().set_x_sampling().set_y_start().set_y_end().set_y_sampling() + self.x_start = SENSOR.DIMENSIONS.X_START + self.y_start = SENSOR.DIMENSIONS.Y_START + self.x_end = SENSOR.DIMENSIONS.X_END + self.y_end = SENSOR.DIMENSIONS.Y_END + self.x_sampling = SENSOR.DIMENSIONS.X_SAMPLING + self.y_sampling = SENSOR.DIMENSIONS.Y_SAMPLING - def set_x_start(self, value: float = -50) -> BaseSensor.Dimensions: + @property + def x_start(self) -> float: + """Set the minimum value on x axis. + + By default, ``-50``. + + Returns + ------- + float + minimum value in x axis + """ + return self._sensor_dimensions.x_start + + @x_start.setter + def x_start(self, value: float): """Set the minimum value on x axis. Parameters ---------- value : float Minimum value on x axis (mm). - By default, ``-50``. + """ + self._sensor_dimensions.x_start = value + + @property + def x_end(self) -> float: + """Set the maximum value on x axis. + + By default, ``50``. Returns ------- - ansys.speos.core.sensor.BaseSensor.Dimensions - Dimensions. + float + maximum value on x axis. """ - self._sensor_dimensions.x_start = value - return self + return self._sensor_dimensions.x_end - def set_x_end(self, value: float = 50) -> BaseSensor.Dimensions: + @x_end.setter + def x_end(self, value: float): """Set the maximum value on x axis. Parameters ---------- value : float Maximum value on x axis (mm). - By default, ``50``. + """ + self._sensor_dimensions.x_end = value + + @property + def x_sampling(self) -> int: + """Set the sampling value on x axis. + + By default, ``100``. Returns ------- - ansys.speos.core.sensor.BaseSensor.Dimensions - Dimensions. + float + sampling value on x axis. """ - self._sensor_dimensions.x_end = value - return self + return self._sensor_dimensions.x_sampling - def set_x_sampling(self, value: int = 100) -> BaseSensor.Dimensions: + @x_sampling.setter + def x_sampling(self, value: int): """Set the sampling value on x axis. Parameters ---------- value : int The number of pixels of the XMP map on x axis. - By default, ``100``. + """ + self._sensor_dimensions.x_sampling = value + + @property + def y_start(self) -> float: + """Set the minimum value on y axis. + + By default, ``-50``. Returns ------- - ansys.speos.core.sensor.BaseSensor.Dimensions - Dimensions. + float + minimum value in y axis """ - self._sensor_dimensions.x_sampling = value - return self + return self._sensor_dimensions.y_start - def set_y_start(self, value: float = -50) -> BaseSensor.Dimensions: + @y_start.setter + def y_start(self, value: float): """Set the minimum value on y axis. Parameters ---------- value : float Minimum value on y axis (mm). - By default, ``-50``. + """ + self._sensor_dimensions.y_start = value + + @property + def y_end(self) -> float: + """Set the maximum value on y axis. + + By default, ``50``. Returns ------- - ansys.speos.core.sensor.BaseSensor.Dimensions - Dimensions. + float + maximum value on y axis. """ - self._sensor_dimensions.y_start = value - return self + return self._sensor_dimensions.y_end - def set_y_end(self, value: float = 50) -> BaseSensor.Dimensions: + @y_end.setter + def y_end(self, value: float): """Set the maximum value on y axis. Parameters ---------- value : float Maximum value on y axis (mm). - By default, ``50``. + """ + self._sensor_dimensions.y_end = value + + @property + def y_sampling(self) -> int: + """Set the sampling value on y axis. + + By default, ``100``. Returns ------- - ansys.speos.core.sensor.BaseSensor.Dimensions - Dimensions. + float + sampling value on y axis. """ - self._sensor_dimensions.y_end = value - return self + return self._sensor_dimensions.y_sampling - def set_y_sampling(self, value: int = 100) -> BaseSensor.Dimensions: + @y_sampling.setter + def y_sampling(self, value: int): """Set the sampling value on y axis. Parameters ---------- value : int The number of pixels of the XMP map on y axis. - By default, ``100``. - - Returns - ------- - ansys.speos.core.sensor.BaseSensor.Dimensions - Dimensions. """ self._sensor_dimensions.y_sampling = value - return self class Colorimetric: """Type of sensor : Colorimetric. @@ -567,6 +627,7 @@ def set_sca_filtering_mode_last_impact( ) return self + # @TODO "refactor to property" def set_layers(self, values: List[BaseSensor.FaceLayer]) -> BaseSensor.LayerTypeFace: """Set the layers. @@ -629,24 +690,32 @@ def __init__( if default_values: # Default values - self.set_maximum_nb_of_sequence().set_define_sequence_per_geometries() + self.maximum_nb_of_sequence = SENSOR.LAYERTYPES.MAXIMUM_NB_OF_SEQUENCE + self.set_define_sequence_per_geometries() - def set_maximum_nb_of_sequence(self, value: int = 10) -> BaseSensor.LayerTypeSequence: + @property + def maximum_nb_of_sequence(self) -> int: + """Set the maximum number of sequences. + + By default, ``10``. + + Returns + ------- + int + maximum number of sequences. + """ + return self._layer_type_sequence.maximum_nb_of_sequence + + @maximum_nb_of_sequence.setter + def maximum_nb_of_sequence(self, value: int): """Set the maximum number of sequences. Parameters ---------- value : int Maximum number of sequences. - By default, ``10``. - - Returns - ------- - ansys.speos.core.sensor.BaseSensor.LayerTypeSequence - LayerTypeSequence. """ self._layer_type_sequence.maximum_nb_of_sequence = value - return self def set_define_sequence_per_geometries( self, @@ -714,7 +783,25 @@ def __init__( # Default values self.set_sampling() - def set_sampling(self, value: int = 9) -> BaseSensor.LayerTypeIncidenceAngle: + @property + def sampling(self) -> BaseSensor.LayerTypeIncidenceAngle: + """Set the sampling for incidence angles. + + Parameters + ---------- + value : int + Sampling for incidence angles. + By default, ``9``. + + Returns + ------- + ansys.speos.core.sensor.BaseSensor.LayerTypeIncidenceAngle + LayerTypeIncidenceAngle. + """ + return self._layer_type_incidence_angle.sampling + + @sampling.setter + def sampling(self, value: int) -> BaseSensor.LayerTypeIncidenceAngle: """Set the sampling for incidence angles. Parameters @@ -729,7 +816,6 @@ def set_sampling(self, value: int = 9) -> BaseSensor.LayerTypeIncidenceAngle: LayerTypeIncidenceAngle. """ self._layer_type_incidence_angle.sampling = value - return self def _to_dict(self) -> dict: out_dict = {} From 0990b59d031b981982ae286340e858f825e45847 Mon Sep 17 00:00:00 2001 From: plu Date: Sat, 2 Aug 2025 13:12:20 +0100 Subject: [PATCH 02/52] refactor SourceLuminaire --- src/ansys/speos/core/source.py | 82 +++++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 21 deletions(-) diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index 583765fc6..d27b43aed 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -26,6 +26,7 @@ import datetime from difflib import SequenceMatcher +from pathlib import Path from typing import List, Mapping, Optional, Union import uuid @@ -455,7 +456,7 @@ def __init__( if default_values: # Default values self.set_flux_from_intensity_file().set_spectrum().set_incandescent() - self.set_axis_system() + self.axis_system = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1] @property def visual_data(self) -> _VisualData: @@ -506,7 +507,19 @@ def set_flux_from_intensity_file(self) -> SourceLuminaire: self._source_template.luminaire.flux_from_intensity_file.SetInParent() return self - def set_flux_luminous(self, value: float = 683) -> SourceLuminaire: + @property + def flux_luminous(self) -> float: + """Get luminous flux. + + Returns + ------- + float + Luminaire source luminous flux value. + """ + return self._source_template.luminaire.luminous_flux.luminous_value + + @flux_luminous.setter + def flux_luminous(self, value: float) -> None: """Set luminous flux. Parameters @@ -517,13 +530,23 @@ def set_flux_luminous(self, value: float = 683) -> SourceLuminaire: Returns ------- - ansys.speos.core.source.SourceLuminaire - Luminaire source. + None """ self._source_template.luminaire.luminous_flux.luminous_value = value - return self - def set_flux_radiant(self, value: float = 1) -> SourceLuminaire: + @property + def flux_radiant(self) -> float: + """Get radiant flux. + + Returns + ------- + float + Luminous flux in radiant. + """ + return self._source_template.luminaire.radiant_flux.radiant_value + + @flux_radiant.setter + def flux_radiant(self, value: float) -> None: """Set radiant flux. Parameters @@ -534,27 +557,35 @@ def set_flux_radiant(self, value: float = 1) -> SourceLuminaire: Returns ------- - ansys.speos.core.source.SourceLuminaire - Luminaire source. + None """ self._source_template.luminaire.radiant_flux.radiant_value = value - return self - def set_intensity_file_uri(self, uri: str) -> SourceLuminaire: + @property + def intensity_file_ur(self) -> str: + """Get intensity file. + + Returns + ------- + str + Intensity file uri. + """ + return self._source_template.luminaire.intensity_file_uri + + @intensity_file_ur.setter + def intensity_file_ur(self, uri: Union[str, Path]) -> None: """Set intensity file. Parameters ---------- - uri : str + uri : Union[str, Path] IES or EULUMDAT format file uri. Returns ------- - ansys.speos.core.source.SourceLuminaire - Luminaire source. + None """ - self._source_template.luminaire.intensity_file_uri = uri - return self + self._source_template.luminaire.intensity_file_uri = str(uri) def set_spectrum(self) -> Spectrum: """Set spectrum. @@ -569,7 +600,20 @@ def set_spectrum(self) -> Spectrum: self._spectrum._message_to_complete = self._source_template.luminaire return self._spectrum._spectrum - def set_axis_system(self, axis_system: Optional[List[float]] = None) -> SourceLuminaire: + @property + def axis_system(self) -> list: + """Get the position of the source. + + Returns + ------- + List[float] + Position of the source [Ox Oy Oz Xx Xy Xz Yx Yy Yz Zx Zy Zz]. + By default, ``[0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]``. + """ + return self._source_instance.luminaire_properties.axis_system[:] + + @axis_system.setter + def axis_system(self, axis_system: list) -> None: """Set the position of the source. Parameters @@ -580,13 +624,9 @@ def set_axis_system(self, axis_system: Optional[List[float]] = None) -> SourceLu Returns ------- - ansys.speos.core.source.SourceLuminaire - Luminaire source. + None """ - if axis_system is None: - axis_system = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1] self._source_instance.luminaire_properties.axis_system[:] = axis_system - return self class SourceRayFile(BaseSource): From e151c5d066b5c159e80a72d6d8e0e19858f19bf6 Mon Sep 17 00:00:00 2001 From: plu Date: Tue, 5 Aug 2025 17:19:14 +0100 Subject: [PATCH 03/52] refactor the spectrum.py --- src/ansys/speos/core/spectrum.py | 315 +++++++++++++++++++++++++++---- 1 file changed, 278 insertions(+), 37 deletions(-) diff --git a/src/ansys/speos/core/spectrum.py b/src/ansys/speos/core/spectrum.py index e508f4799..e036e16fc 100644 --- a/src/ansys/speos/core/spectrum.py +++ b/src/ansys/speos/core/spectrum.py @@ -27,6 +27,8 @@ from typing import List, Mapping, Optional import warnings +from ansys.api.speos.spectrum.v1 import spectrum_pb2 +from ansys.speos.core.generic.constants import SPECTRUM from ansys.speos.core.kernel.client import SpeosClient from ansys.speos.core.kernel.proto_message_utils import protobuf_message_to_dict from ansys.speos.core.kernel.spectrum import ProtoSpectrum @@ -59,6 +61,216 @@ class Spectrum: Link object for the spectrum in database. """ + class Monochromatic: + """Monochromatic type of spectrum. + + By default, monochromatic spectrum wavelength is set to be 550. + + Parameters + ---------- + monochromatic : ansys.api.speos.spectrum.v1.spectrum_pb2.Monochromatic + Monochromatic protobuf object to modify. + default_values : bool + Uses default values when True. + stable_ctr : bool + Variable to indicate if usage is inside class scope + + Notes + ----- + **Do not instantiate this class yourself**, use set_monochromatic method available in + Spectrum classes. + """ + + def __init__( + self, + monochromatic: spectrum_pb2.Monochromatic, + default_values: bool = True, + stable_ctr: bool = False, + ): + if not stable_ctr: + msg = "WavelengthsRange class instantiated outside of class scope" + raise RuntimeError(msg) + self._monochromatic = monochromatic + + if default_values: + self.wavelength = SPECTRUM.MONOCHROMATIC.WAVELENGTH + + @property + def wavelength(self) -> float: + """Get the wavelength of the spectrum. + + Returns + ------- + float + Wavelength of the spectrum. + """ + return self._monochromatic.wavelength + + @wavelength.setter + def wavelength(self, value: float) -> None: + """Set the wavelength of the spectrum. + + Parameters + ---------- + value: float + Wavelength of the spectrum. + + Returns + ------- + None + + """ + self._monochromatic.wavelength = value + + class Blackbody: + """Blackbody type of spectrum. + + By default, Blackbody temperature is set to be 2856. + + Parameters + ---------- + blackbody : ansys.api.speos.spectrum.v1.spectrum_pb2.Blackbody + Blackbody protobuf object to modify. + default_values : bool + Uses default values when True. + stable_ctr : bool + Variable to indicate if usage is inside class scope + + Notes + ----- + **Do not instantiate this class yourself**, use set_blackbody method available in + Spectrum classes. + """ + + def __init__( + self, + blackbody: spectrum_pb2.BlackBody, + default_values: bool = True, + stable_ctr: bool = False, + ): + if not stable_ctr: + msg = "WavelengthRange class instantiated outside of class scope" + raise RuntimeError(msg) + self._blackbody = blackbody + + if default_values: + self.temperature = SPECTRUM.BLACKBODY.TEMPERATURE + + @property + def temperature(self) -> float: + """Get the temperature of the spectrum. + + Returns + ------- + float + Temperature of the spectrum. + + """ + return self._blackbody.temperature + + @temperature.setter + def temperature(self, value: float) -> None: + """Set the temperature of the spectrum. + + Parameters + ---------- + value: float + Temperature of the spectrum. + + Returns + ------- + None + + """ + self._blackbody.temperature = value + + class Sampled: + """Sampled type of spectrum. + + By default, Sampled temperature is set to be 2856. + + Parameters + ---------- + sampled : ansys.api.speos.spectrum.v1.spectrum_pb2.Sampled + Sampled protobuf object to modify. + default_values : bool + Uses default values when True. + stable_ctr : bool + Variable to indicate if usage is inside class scope + + Notes + ----- + **Do not instantiate this class yourself**, use set_sampled method available in + Spectrum classes. + """ + + def __init__( + self, + sampled: spectrum_pb2.sampled, + default_values: bool = True, + stable_ctr: bool = False, + ): + if not stable_ctr: + msg = "WavelengthRange class instantiated outside of class scope" + raise RuntimeError(msg) + self._sampled = sampled + # if default_values: + # + + @property + def wavelengths(self) -> List[float]: + """Get the wavelength values of the spectrum. + + Returns + ------- + List[float] + Wavelength values of the spectrum. + + """ + return self._sampled.wavelengths[:] + + @wavelengths.setter + def wavelengths(self, wavelengths: list[float]) -> None: + """Set the wavelength values of the spectrum. + + Parameters + ---------- + wavelengths: List[float] + Wavelength values of the spectrum. + + Returns + ------- + None + + """ + self._sampled.wavelengths = wavelengths + + @property + def values(self) -> List[float]: + """Get the values of the spectrum sampled wavelengths. + + Returns + ------- + List[float] + List of values, expected from 0. to 100. in %. + """ + return self._sampled.values + + @values.setter + def values(self, values: list[float]) -> None: + """Set the values of the spectrum sampled wavelengths. + + Parameters + ---------- + values: List[float] + List of values, expected from 0. to 100. in %. + + Returns + ------- + None + """ + self._sampled.values[:] = values + def __init__( self, speos_client: SpeosClient, @@ -74,6 +286,9 @@ def __init__( if metadata is None: metadata = {} + # Attribute gathering more complex spectrun type + self._type = None + if key == "": # Create Spectrum self._spectrum = ProtoSpectrum(name=name, description=description, metadata=metadata) @@ -85,58 +300,84 @@ def __init__( self.spectrum_link = speos_client[key] self._spectrum = self.spectrum_link.get() - def set_monochromatic(self, wavelength: float = 555.0) -> Spectrum: + def set_monochromatic(self) -> Spectrum.Monochromatic: """Set the spectrum as monochromatic. - Parameters - ---------- - wavelength : float - Wavelength of the spectrum, in nm. - By default, ``555.0``. - Returns ------- - ansys.speos.core.spectrum.Spectrum - Spectrum feature. + ansys.speos.core.spectrum.Spectrum.Monochromatic + Spectrum Monochromatic feature. """ - self._spectrum.monochromatic.wavelength = wavelength - return self - - def set_blackbody(self, temperature: float = 2856) -> Spectrum: + if self._type is None and self._spectrum.HasField("monochromatic"): + self._type = Spectrum.Monochromatic( + monochromatic=self._spectrum.monochromatic, + default_values=False, + stable_ctr=True, + ) + elif not isinstance(self._type, Spectrum.Monochromatic): + self._type = Spectrum.Monochromatic( + monochromatic=self._spectrum.monochromatic, + default_values=True, + stable_ctr=True, + ) + elif self._type._monochromatic is not self._spectrum.monochromatic: + self._type._monochromatic = self._spectrum.monochromatic + return self._type + # self._spectrum.monochromatic.wavelength = wavelength + # return self + + def set_blackbody(self) -> Spectrum.Blackbody: """Set the spectrum as blackbody. - Parameters - ---------- - temperature : float - Temperature of the blackbody, in K. - By default, ``2856``. - Returns ------- - ansys.speos.core.spectrum.Spectrum - Spectrum feature. + ansys.speos.core.spectrum.Spectrum.Blackbody + Spectrum Blackbody feature. """ - self._spectrum.blackbody.temperature = temperature - return self - - def set_sampled(self, wavelengths: List[float], values: List[float]) -> Spectrum: + if self._type is None and self._spectrum.HasField("blackbody"): + self._type = Spectrum.Blackbody( + blackbody=self._spectrum.blackbody, + default_values=False, + stable_ctr=True, + ) + elif not isinstance(self._type, Spectrum.Blackbody): + self._type = Spectrum.Blackbody( + blackbody=self._spectrum.blackbody, + default_values=True, + stable_ctr=True, + ) + elif self._type._blackbody is not self._spectrum.blackbody: + self._type._blackbody = self._spectrum.blackbody + return self._type + # self._spectrum.blackbody.temperature = temperature + # return self + + def set_sampled(self) -> Spectrum.Sampled: """Set the spectrum as sampled. - Parameters - ---------- - wavelengths : List[float] - List of wavelengths, in nm - values : List[float] - List of values, expected from 0. to 100. in % - Returns ------- - ansys.speos.core.spectrum.Spectrum - Spectrum feature. + ansys.speos.core.spectrum.Spectrum.Sampled + Spectrum Sampled feature. """ - self._spectrum.sampled.wavelengths[:] = wavelengths - self._spectrum.sampled.values[:] = values - return self + if self._type is None and self._spectrum.HasField("sampled"): + self._type = Spectrum.Sampled( + sampled=self._spectrum.sampled, + default_values=False, + stable_ctr=True, + ) + elif not isinstance(self._type, Spectrum.Sampled): + self._type = Spectrum.Sampled( + sampled=self._spectrum.sampled, + default_values=True, + stable_ctr=True, + ) + elif self._type._sampled is not self._spectrum.sampled: + self._type._sampled = self._spectrum.sampled + return self._type + # self._spectrum.sampled.wavelengths[:] = wavelengths + # self._spectrum.sampled.values[:] = values + # return self def set_library(self, file_uri: str) -> Spectrum: """Set the spectrum as library. From 2112d08875a9db478fb6f5202b2a245e29483a4e Mon Sep 17 00:00:00 2001 From: plu Date: Tue, 5 Aug 2025 17:20:03 +0100 Subject: [PATCH 04/52] refactor the luminaire source class --- src/ansys/speos/core/source.py | 216 ++++++++++++++++++++++++++------- 1 file changed, 171 insertions(+), 45 deletions(-) diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index d27b43aed..f5f757462 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -33,12 +33,14 @@ import numpy as np from ansys.api.speos.scene.v2 import scene_pb2 +from ansys.api.speos.source.v1 import source_pb2 from ansys.speos.core import ( project as project, proto_message_utils as proto_message_utils, ) import ansys.speos.core.body as body import ansys.speos.core.face as face +from ansys.speos.core.generic.constants import SOURCE import ansys.speos.core.generic.general_methods as general_methods from ansys.speos.core.generic.visualization_methods import _VisualArrow, _VisualData from ansys.speos.core.geo_ref import GeoRef @@ -425,6 +427,129 @@ class SourceLuminaire(BaseSource): Uses default values when True. """ + class Luminous: + """Luminous type of flux. + + By default, Luminous flux value is set to be 683 lm. + + Parameters + ---------- + luminous_flux : ansys.api.speos.source.v1.source_pb2.Luminous + Luminous protobuf object to modify. + default_values : bool + Uses default values when True. + stable_ctr : bool + Variable to indicate if usage is inside class scope + + Notes + ----- + **Do not instantiate this class yourself**, use set_flux_luminous method available in + SourceLuminaire classes. + """ + + def __init__( + self, + luminous_flux: source_pb2.Luminous, + default_values: bool = True, + stable_ctr: bool = False, + ): + if not stable_ctr: + msg = "Luminous class instantiated outside of class scope" + raise RuntimeError(msg) + self._luminous_flux = luminous_flux + + if default_values: + self.value = SOURCE.LUMINOUS.VALUE + + @property + def value(self) -> float: + """Get luminous flux value. + + Returns + ------- + float + Luminous flux value. + """ + return self._luminous_flux.luminous_value + + @value.setter + def value(self, value: float) -> None: + """Set luminous flux value. + + Parameters + ---------- + value: float + Luminous flux value. + + Returns + ------- + None + + """ + self._luminous_flux.luminous_value = value + + class Radiant: + """Radiant type of flux. + + By default, Radiant flux value is set to be 1 W. + + Parameters + ---------- + radiant_flux : ansys.api.speos.source.v1.source_pb2.Radiant + Radiant protobuf object to modify. + default_values : bool + Uses default values when True. + stable_ctr : bool + Variable to indicate if usage is inside class scope + + Notes + ----- + **Do not instantiate this class yourself**, use set_flux_radiant method available in + SourceLuminaire classes. + """ + + def __init__( + self, + radiant_flux: source_pb2.Radiant, + default_values: bool = True, + stable_ctr: bool = False, + ): + if not stable_ctr: + msg = "Radiant class instantiated outside of class scope" + raise RuntimeError(msg) + self._radiant_flux = radiant_flux + + if default_values: + self.value = SOURCE.RADIANT.VALUE + + @property + def value(self) -> float: + """Get radiant flux value. + + Returns + ------- + float + Radiant flux value. + + """ + return self._radiant_flux.radiant_value + + @value.setter + def value(self, value: float) -> None: + """Set radiant flux value. + + Parameters + ---------- + value: float + Radiant flux value. + + Returns + ------- + None + + """ + self._radiant_flux.radiant_value = value + @general_methods.min_speos_version(25, 2, 0) def __init__( self, @@ -446,6 +571,9 @@ def __init__( source_instance=source_instance, ) + # Attribute gathering more complex flux type + self._type = None + self._spectrum = self._Spectrum( speos_client=self._project.client, name=name, @@ -507,62 +635,60 @@ def set_flux_from_intensity_file(self) -> SourceLuminaire: self._source_template.luminaire.flux_from_intensity_file.SetInParent() return self - @property - def flux_luminous(self) -> float: - """Get luminous flux. - - Returns - ------- - float - Luminaire source luminous flux value. - """ - return self._source_template.luminaire.luminous_flux.luminous_value - - @flux_luminous.setter - def flux_luminous(self, value: float) -> None: + def set_flux_luminous(self) -> SourceLuminaire.Luminous: """Set luminous flux. - Parameters - ---------- - value : float - Luminous flux in lumens. - By default, ``683.0``. - - Returns - ------- - None - """ - self._source_template.luminaire.luminous_flux.luminous_value = value - - @property - def flux_radiant(self) -> float: - """Get radiant flux. - Returns ------- - float - Luminous flux in radiant. + ansys.speos.core.source.SourceLuminaire.Luminous + Luminaire source. """ - return self._source_template.luminaire.radiant_flux.radiant_value + if self._type is None and self._source_template.luminaire.HasField("luminous_flux"): + self._type = SourceLuminaire.Luminous( + luminous_flux=self._source_template.luminaire.luminous_flux, + default_values=False, + stable_ctr=True, + ) + elif not isinstance(self._type, SourceLuminaire.Luminous): + self._type = SourceLuminaire.Luminous( + luminous_flux=self._source_template.luminaire.luminous_flux, + default_values=True, + stable_ctr=True, + ) + elif self._type._luminous_flux is not self._source_template.luminaire.luminous_flux: + self._type._luminous_flux = self._source_template.luminaire.luminous_flux + return self._type + # self._source_template.luminaire.luminous_flux.luminous_value = value + # return self - @flux_radiant.setter - def flux_radiant(self, value: float) -> None: + def set_flux_radiant(self) -> SourceLuminaire.Radiant: """Set radiant flux. - Parameters - ---------- - value : float - Radiant flux in watts. - By default, ``1.0``. - Returns ------- - None + ansys.speos.core.source.SourceLuminaire.Radiant + Luminaire source. """ - self._source_template.luminaire.radiant_flux.radiant_value = value + if self._type is None and self._source_template.luminaire.HasField("radiant_flux"): + self._type = SourceLuminaire.Radiant( + radiant_flux=self._source_template.luminaire.radiant_flux, + default_values=False, + stable_ctr=True, + ) + elif not isinstance(self._type, SourceLuminaire.Radiant): + self._type = SourceLuminaire.Radiant( + radiant_flux=self._source_template.luminaire.radiant_flux, + default_values=True, + stable_ctr=True, + ) + elif self._type._radiant_flux is not self._source_template.luminaire.radiant_flux: + self._type._radiant_flux = self._source_template.luminaire.radiant_flux + return self._type + # self._source_template.luminaire.radiant_flux.radiant_value = value + # return self @property - def intensity_file_ur(self) -> str: + def intensity_file_uri(self) -> str: """Get intensity file. Returns @@ -572,8 +698,8 @@ def intensity_file_ur(self) -> str: """ return self._source_template.luminaire.intensity_file_uri - @intensity_file_ur.setter - def intensity_file_ur(self, uri: Union[str, Path]) -> None: + @intensity_file_uri.setter + def intensity_file_uri(self, uri: Union[str, Path]) -> None: """Set intensity file. Parameters From 1b62c6d41a5aeff65f74fef0ceb6a638cb148c2a Mon Sep 17 00:00:00 2001 From: plu Date: Tue, 5 Aug 2025 17:20:36 +0100 Subject: [PATCH 05/52] luminaire and spectrum constant values in constants.py --- src/ansys/speos/core/generic/constants.py | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/ansys/speos/core/generic/constants.py b/src/ansys/speos/core/generic/constants.py index 4cca3ff33..d748f59a9 100644 --- a/src/ansys/speos/core/generic/constants.py +++ b/src/ansys/speos/core/generic/constants.py @@ -40,6 +40,34 @@ """ +class SPECTRUM: + """Constant class for Spectrum.""" + + class MONOCHROMATIC: + """Constant class for Monochromatic.""" + + WAVELENGTH = 550 + + class BLACKBODY: + """Constant class for BlackBody.""" + + TEMPERATURE = 2856 + + +class SOURCE: + """Constant class for Sources.""" + + class LUMINOUS: + """Constant class for Luminous.""" + + VALUE = 683 + + class RADIANT: + """Constant class for Radiant.""" + + VALUE = 1 + + class SENSOR: """Constant class for Sensors.""" From e8d2d27b41e4d13377acf1c4aac2f08896829c80 Mon Sep 17 00:00:00 2001 From: plu Date: Tue, 5 Aug 2025 17:21:09 +0100 Subject: [PATCH 06/52] update the test related to luminaire source class --- tests/core/test_source.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/tests/core/test_source.py b/tests/core/test_source.py index 3a679b110..80cc798d1 100644 --- a/tests/core/test_source.py +++ b/tests/core/test_source.py @@ -65,7 +65,7 @@ def test_create_luminaire_source(speos: Speos): ] # intensity_file_uri - source1.set_intensity_file_uri(uri=str(Path(test_path) / "IES_C_DETECTOR.ies")) + source1.intensity_file_uri = Path(test_path) / "IES_C_DETECTOR.ies" source1.commit() assert source1.source_template_link is not None assert source1.source_template_link.get().luminaire.intensity_file_uri != "" @@ -78,14 +78,16 @@ def test_create_luminaire_source(speos: Speos): assert spectrum.get().predefined.HasField("halogen") # flux luminous_flux - source1.set_flux_luminous(value=650) + source1.set_flux_luminous().value = 650 source1.commit() + assert source1.set_flux_luminous().value == 650 assert source1.source_template_link.get().luminaire.HasField("luminous_flux") assert source1.source_template_link.get().luminaire.luminous_flux.luminous_value == 650 # flux radiant_flux - source1.set_flux_radiant(value=1.2) + source1.set_flux_radiant().value = 1.2 source1.commit() + assert source1.set_flux_radiant().value == 1.2 assert source1.source_template_link.get().luminaire.HasField("radiant_flux") assert source1.source_template_link.get().luminaire.radiant_flux.radiant_value == 1.2 @@ -95,8 +97,10 @@ def test_create_luminaire_source(speos: Speos): assert source1.source_template_link.get().luminaire.HasField("flux_from_intensity_file") # Properties : axis_system - source1.set_axis_system(axis_system=[10, 20, 10, 1, 0, 0, 0, 1, 0, 0, 0, 1]) + source1.axis_system = [10, 20, 10, 1, 0, 0, 0, 1, 0, 0, 0, 1] + # source1.set_axis_system(axis_system=[10, 20, 10, 1, 0, 0, 0, 1, 0, 0, 0, 1]) source1.commit() + assert source1.axis_system == [10, 20, 10, 1, 0, 0, 0, 1, 0, 0, 0, 1] assert source1._source_instance.HasField("luminaire_properties") assert source1._source_instance.luminaire_properties.axis_system == [ 10, @@ -559,7 +563,7 @@ def test_keep_same_internal_feature(speos: Speos): # LUMINAIRE SOURCE source2 = SourceLuminaire(project=p, name="Luminaire.1") - source2.set_intensity_file_uri(uri=str(Path(test_path) / "IES_C_DETECTOR.ies")) + source2.intensity_file_uri = Path(test_path) / "IES_C_DETECTOR.ies" source2.commit() spectrum_guid = source2.source_template_link.get().luminaire.spectrum_guid @@ -653,9 +657,8 @@ def test_luminaire_modify_after_reset(speos: Speos): # Create + commit source = SourceLuminaire(project=p, name="Luminaire.1") - source.set_intensity_file_uri( - uri=str(Path(test_path) / "IES_C_DETECTOR.ies") - ).set_flux_luminous() + source.intensity_file_uri = Path(test_path) / "IES_C_DETECTOR.ies" + source.set_flux_luminous() source.commit() # Ask for reset @@ -663,8 +666,9 @@ def test_luminaire_modify_after_reset(speos: Speos): # Modify after a reset # Template + assert source.set_flux_luminous().value == 683 assert source._source_template.luminaire.luminous_flux.luminous_value == 683 - source.set_flux_luminous(value=500) + source.set_flux_luminous().value = 500 assert source._source_template.luminaire.luminous_flux.luminous_value == 500 # Intermediate class for spectrum @@ -687,7 +691,7 @@ def test_luminaire_modify_after_reset(speos: Speos): 0, 1, ] - source.set_axis_system([50, 20, 10, 1, 0, 0, 0, 1, 0, 0, 0, 1]) + source.axis_system = [50, 20, 10, 1, 0, 0, 0, 1, 0, 0, 0, 1] assert source._source_instance.luminaire_properties.axis_system == [ 50, 20, @@ -866,7 +870,7 @@ def test_print_source(speos: Speos): # Create + commit # source = p.create_source(name="Luminaire.1") source = SourceLuminaire(project=p, name="Luminaire.1") - source.set_intensity_file_uri(uri=str(Path(test_path) / "IES_C_DETECTOR.ies")) + source.intensity_file_uri = Path(test_path) / "IES_C_DETECTOR.ies" source.commit() # Retrieve print From c11dc96b292fb2056fd9e000a64918aedac41d1d Mon Sep 17 00:00:00 2001 From: plu Date: Tue, 5 Aug 2025 17:21:39 +0100 Subject: [PATCH 07/52] update the source example related to luminaire source --- examples/core/source.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/core/source.py b/examples/core/source.py index e30e77aca..123a6ed80 100644 --- a/examples/core/source.py +++ b/examples/core/source.py @@ -96,7 +96,7 @@ def create_face(body): 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) +source1.intensity_file_uri = intensity_file_path print(source1) # **Push it to the server.** @@ -114,10 +114,10 @@ def create_face(body): 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 +source2.intensity_file_uri = intensity_file_path +source2.flux_radiant = 1.0 # select flux radiant # 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.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) @@ -140,8 +140,8 @@ def create_face(body): # > changes. # > If you don't, you will still only watch what is committed on the server. -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.flux_radiant = 1.2 # modify radiant flux value +source1.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) @@ -150,7 +150,7 @@ def create_face(body): # # Possibility to reset local values from the one available in the server. -source1.set_flux_luminous() # modify to luminous flux BUT no commit +source1.flux_luminous = 683.0 # 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 From 359eeb62a9ae4ba5f3b44b26cf80aec7683e64a0 Mon Sep 17 00:00:00 2001 From: plu Date: Tue, 5 Aug 2025 17:29:50 +0100 Subject: [PATCH 08/52] refactor the Luminous and Radiant to BaseSource class --- src/ansys/speos/core/source.py | 252 ++++++++++++++++----------------- 1 file changed, 126 insertions(+), 126 deletions(-) diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index f5f757462..ead651e65 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -109,6 +109,129 @@ def __init__( self.source_template_link = self._project.client[source_instance.source_guid] self._reset() + class Luminous: + """Luminous type of flux. + + By default, Luminous flux value is set to be 683 lm. + + Parameters + ---------- + luminous_flux : ansys.api.speos.source.v1.source_pb2.Luminous + Luminous protobuf object to modify. + default_values : bool + Uses default values when True. + stable_ctr : bool + Variable to indicate if usage is inside class scope + + Notes + ----- + **Do not instantiate this class yourself**, use set_flux_luminous method available in + Source classes. + """ + + def __init__( + self, + luminous_flux: source_pb2.Luminous, + default_values: bool = True, + stable_ctr: bool = False, + ): + if not stable_ctr: + msg = "Luminous class instantiated outside of class scope" + raise RuntimeError(msg) + self._luminous_flux = luminous_flux + + if default_values: + self.value = SOURCE.LUMINOUS.VALUE + + @property + def value(self) -> float: + """Get luminous flux value. + + Returns + ------- + float + Luminous flux value. + """ + return self._luminous_flux.luminous_value + + @value.setter + def value(self, value: float) -> None: + """Set luminous flux value. + + Parameters + ---------- + value: float + Luminous flux value. + + Returns + ------- + None + + """ + self._luminous_flux.luminous_value = value + + class Radiant: + """Radiant type of flux. + + By default, Radiant flux value is set to be 1 W. + + Parameters + ---------- + radiant_flux : ansys.api.speos.source.v1.source_pb2.Radiant + Radiant protobuf object to modify. + default_values : bool + Uses default values when True. + stable_ctr : bool + Variable to indicate if usage is inside class scope + + Notes + ----- + **Do not instantiate this class yourself**, use set_flux_radiant method available in + Source classes. + """ + + def __init__( + self, + radiant_flux: source_pb2.Radiant, + default_values: bool = True, + stable_ctr: bool = False, + ): + if not stable_ctr: + msg = "Radiant class instantiated outside of class scope" + raise RuntimeError(msg) + self._radiant_flux = radiant_flux + + if default_values: + self.value = SOURCE.RADIANT.VALUE + + @property + def value(self) -> float: + """Get radiant flux value. + + Returns + ------- + float + Radiant flux value. + + """ + return self._radiant_flux.radiant_value + + @value.setter + def value(self, value: float) -> None: + """Set radiant flux value. + + Parameters + ---------- + value: float + Radiant flux value. + + Returns + ------- + None + + """ + self._radiant_flux.radiant_value = value + class _Spectrum: def __init__( self, @@ -427,129 +550,6 @@ class SourceLuminaire(BaseSource): Uses default values when True. """ - class Luminous: - """Luminous type of flux. - - By default, Luminous flux value is set to be 683 lm. - - Parameters - ---------- - luminous_flux : ansys.api.speos.source.v1.source_pb2.Luminous - Luminous protobuf object to modify. - default_values : bool - Uses default values when True. - stable_ctr : bool - Variable to indicate if usage is inside class scope - - Notes - ----- - **Do not instantiate this class yourself**, use set_flux_luminous method available in - SourceLuminaire classes. - """ - - def __init__( - self, - luminous_flux: source_pb2.Luminous, - default_values: bool = True, - stable_ctr: bool = False, - ): - if not stable_ctr: - msg = "Luminous class instantiated outside of class scope" - raise RuntimeError(msg) - self._luminous_flux = luminous_flux - - if default_values: - self.value = SOURCE.LUMINOUS.VALUE - - @property - def value(self) -> float: - """Get luminous flux value. - - Returns - ------- - float - Luminous flux value. - """ - return self._luminous_flux.luminous_value - - @value.setter - def value(self, value: float) -> None: - """Set luminous flux value. - - Parameters - ---------- - value: float - Luminous flux value. - - Returns - ------- - None - - """ - self._luminous_flux.luminous_value = value - - class Radiant: - """Radiant type of flux. - - By default, Radiant flux value is set to be 1 W. - - Parameters - ---------- - radiant_flux : ansys.api.speos.source.v1.source_pb2.Radiant - Radiant protobuf object to modify. - default_values : bool - Uses default values when True. - stable_ctr : bool - Variable to indicate if usage is inside class scope - - Notes - ----- - **Do not instantiate this class yourself**, use set_flux_radiant method available in - SourceLuminaire classes. - """ - - def __init__( - self, - radiant_flux: source_pb2.Radiant, - default_values: bool = True, - stable_ctr: bool = False, - ): - if not stable_ctr: - msg = "Radiant class instantiated outside of class scope" - raise RuntimeError(msg) - self._radiant_flux = radiant_flux - - if default_values: - self.value = SOURCE.RADIANT.VALUE - - @property - def value(self) -> float: - """Get radiant flux value. - - Returns - ------- - float - Radiant flux value. - - """ - return self._radiant_flux.radiant_value - - @value.setter - def value(self, value: float) -> None: - """Set radiant flux value. - - Parameters - ---------- - value: float - Radiant flux value. - - Returns - ------- - None - - """ - self._radiant_flux.radiant_value = value - @general_methods.min_speos_version(25, 2, 0) def __init__( self, @@ -727,7 +727,7 @@ def set_spectrum(self) -> Spectrum: return self._spectrum._spectrum @property - def axis_system(self) -> list: + def axis_system(self) -> list[float]: """Get the position of the source. Returns @@ -739,12 +739,12 @@ def axis_system(self) -> list: return self._source_instance.luminaire_properties.axis_system[:] @axis_system.setter - def axis_system(self, axis_system: list) -> None: + def axis_system(self, axis_system: list[float]) -> None: """Set the position of the source. Parameters ---------- - axis_system : Optional[List[float]] + axis_system : List[float] Position of the source [Ox Oy Oz Xx Xy Xz Yx Yy Yz Zx Zy Zz]. By default, ``[0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]``. From 85ae2f18b9626720ee2deb0ca23cd80211cd526f Mon Sep 17 00:00:00 2001 From: plu Date: Wed, 6 Aug 2025 09:08:08 +0100 Subject: [PATCH 09/52] refactor rayfile source --- src/ansys/speos/core/source.py | 163 ++++++++++++++++++++++++--------- 1 file changed, 121 insertions(+), 42 deletions(-) diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index ead651e65..1efe7d862 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -641,7 +641,7 @@ def set_flux_luminous(self) -> SourceLuminaire.Luminous: Returns ------- ansys.speos.core.source.SourceLuminaire.Luminous - Luminaire source. + Luminaire luminous flux type source. """ if self._type is None and self._source_template.luminaire.HasField("luminous_flux"): self._type = SourceLuminaire.Luminous( @@ -667,7 +667,7 @@ def set_flux_radiant(self) -> SourceLuminaire.Radiant: Returns ------- ansys.speos.core.source.SourceLuminaire.Radiant - Luminaire source. + Luminaire radiant flux type source. """ if self._type is None and self._source_template.luminaire.HasField("radiant_flux"): self._type = SourceLuminaire.Radiant( @@ -811,11 +811,13 @@ def __init__( self.set_spectrum_from_ray_file() self._name = name + # Attribute gathering more complex flux type + self._type = None if default_values: # Default values self.set_flux_from_ray_file().set_spectrum_from_ray_file() - self.set_axis_system() + self.axis_system = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1] @property def visual_data(self) -> _VisualData: @@ -855,21 +857,49 @@ def visual_data(self) -> _VisualData: self._visual_data.updated = True return self._visual_data - def set_ray_file_uri(self, uri: str) -> SourceRayFile: - """Set ray file. + @property + def ray_file_uri(self) -> str: + """Gets ray file URI. + + Returns + ------- + str + Ray file URI. + + """ + return self._source_template.rayfile.ray_file_uri + + @ray_file_uri.setter + def ray_file_uri(self, uri: Union[Path, str]) -> None: + """Set ray file URI. Parameters ---------- - uri : str - Rayfile format file uri (.ray or .tm25ray files expected). + uri: Union[Path, str] + Ray file URI. Returns ------- - ansys.speos.core.source.SourceRayFile - RayFile source. + None + """ - self._source_template.rayfile.ray_file_uri = uri - return self + self._source_template.rayfile.ray_file_uri = str(uri) + + # def set_ray_file_uri(self, uri: str) -> SourceRayFile: + # """Set ray file. + # + # Parameters + # ---------- + # uri : str + # Rayfile format file uri (.ray or .tm25ray files expected). + # + # Returns + # ------- + # ansys.speos.core.source.SourceRayFile + # RayFile source. + # """ + # self._source_template.rayfile.ray_file_uri = uri + # return self def set_flux_from_ray_file(self) -> SourceRayFile: """Take flux from ray file provided. @@ -882,39 +912,57 @@ def set_flux_from_ray_file(self) -> SourceRayFile: self._source_template.rayfile.flux_from_ray_file.SetInParent() return self - def set_flux_luminous(self, value: float = 683) -> SourceRayFile: + def set_flux_luminous(self) -> SourceRayFile.Luminous: """Set luminous flux. - Parameters - ---------- - value : float - Luminous flux in lumens. - By default, ``683.0``. - Returns ------- - ansys.speos.core.source.SourceRayFile - RayFile source. + ansys.speos.core.source.SourceRayFile.Luminous + Luminous flux type source. """ - self._source_template.rayfile.luminous_flux.luminous_value = value - return self + if self._type is None and self._source_template.rayfile.HasField("luminous_flux"): + self._type = SourceRayFile.Luminous( + luminous_flux=self._source_template.rayfile.luminous_flux, + default_values=False, + stable_ctr=True, + ) + elif not isinstance(self._type, SourceRayFile.Luminous): + self._type = SourceRayFile.Luminous( + luminous_flux=self._source_template.rayfile.luminous_flux, + default_values=True, + stable_ctr=True, + ) + elif self._type._luminous_flux is not self._source_template.rayfile.luminous_flux: + self._type._luminous_flux = self._source_template.rayfile.luminous_flux + return self._type + # self._source_template.rayfile.luminous_flux.luminous_value = value + # return self - def set_flux_radiant(self, value: float = 1) -> SourceRayFile: + def set_flux_radiant(self) -> SourceRayFile.Radiant: """Set radiant flux. - Parameters - ---------- - value : float - Radiant flux in watts. - By default, ``1.0``. - Returns ------- - ansys.speos.core.source.SourceRayFile - RayFile source. + ansys.speos.core.source.SourceRayFile.Radiant + Radiant flux type source. """ - self._source_template.rayfile.radiant_flux.radiant_value = value - return self + if self._type is None and self._source_template.rayfile.HasField("radiant_flux"): + self._type = SourceRayFile.Radiant( + radiant_flux=self._source_template.rayfile.radiant_flux, + default_values=False, + stable_ctr=True, + ) + elif not isinstance(self._type, SourceRayFile.Radiant): + self._type = SourceRayFile.Radiant( + radiant_flux=self._source_template.rayfile.radiant_flux, + default_values=True, + stable_ctr=True, + ) + elif self._type._radiant_flux is not self._source_template.rayfile.radiant_flux: + self._type._radiant_flux = self._source_template.rayfile.radiant_flux + return self._type + # self._source_template.rayfile.radiant_flux.radiant_value = value + # return self def set_spectrum_from_ray_file(self) -> SourceRayFile: """Take spectrum from ray file provided. @@ -949,24 +997,55 @@ def set_spectrum(self) -> Spectrum: self._spectrum._no_spectrum_local = False return self._spectrum._spectrum - def set_axis_system(self, axis_system: Optional[List[float]] = None) -> SourceRayFile: - """Set position of the source. + @property + def axis_system(self) -> list[float]: + """Get the axis system of the Source. + + Returns + ------- + list[float] + Position of the rayfile source [Ox Oy Oz Xx Xy Xz Yx Yy Yz Zx Zy Zz]. + By default, ``[0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]``. + + """ + return self._source_instance.rayfile_properties.axis_system[:] + + @axis_system.setter + def axis_system(self, axis_system: list[float]) -> None: + """ + Set the axis system of the Source. Parameters ---------- - axis_system : Optional[List[float]] - Position of the source [Ox Oy Oz Xx Xy Xz Yx Yy Yz Zx Zy Zz]. + axis_system: list[float] + Position of the rayfile source [Ox Oy Oz Xx Xy Xz Yx Yy Yz Zx Zy Zz]. By default, ``[0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]``. Returns ------- - ansys.speos.core.source.SourceRayFile - RayFile Source. + None + """ - if axis_system is None: - axis_system = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1] self._source_instance.rayfile_properties.axis_system[:] = axis_system - return self + + # def set_axis_system(self, axis_system: Optional[List[float]] = None) -> SourceRayFile: + # """Set position of the source. + # + # Parameters + # ---------- + # axis_system : Optional[List[float]] + # Position of the source [Ox Oy Oz Xx Xy Xz Yx Yy Yz Zx Zy Zz]. + # By default, ``[0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]``. + # + # Returns + # ------- + # ansys.speos.core.source.SourceRayFile + # RayFile Source. + # """ + # if axis_system is None: + # axis_system = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1] + # self._source_instance.rayfile_properties.axis_system[:] = axis_system + # return self def set_exit_geometries(self, exit_geometries: Optional[List[GeoRef]] = None) -> SourceRayFile: """Set exit geometries. From 30744e727219b8415d8079507487d6e5b69db32c Mon Sep 17 00:00:00 2001 From: plu Date: Wed, 6 Aug 2025 09:08:46 +0100 Subject: [PATCH 10/52] refactor the test and example using new rayfile source methods --- examples/core/source.py | 2 +- tests/core/test_source.py | 49 ++++++++++++++++++++++----------------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/examples/core/source.py b/examples/core/source.py index 123a6ed80..08c72dec9 100644 --- a/examples/core/source.py +++ b/examples/core/source.py @@ -178,7 +178,7 @@ def create_face(body): 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.ray_file_uri = ray_file_path source3.commit() print(source3) # - diff --git a/tests/core/test_source.py b/tests/core/test_source.py index 80cc798d1..444ba5b29 100644 --- a/tests/core/test_source.py +++ b/tests/core/test_source.py @@ -297,7 +297,7 @@ def test_create_rayfile_source(speos: Speos): assert source1._source_template.rayfile.ray_file_uri == "" # ray_file_uri - source1.set_ray_file_uri(uri=str(Path(test_path) / "Rays.ray")) + source1.ray_file_uri = Path(test_path) / "Rays.ray" source1.commit() assert source1.source_template_link is not None assert source1.source_template_link.get().HasField("rayfile") @@ -306,14 +306,16 @@ def test_create_rayfile_source(speos: Speos): assert source1.source_template_link.get().rayfile.HasField("spectrum_from_ray_file") # luminous_flux - source1.set_flux_luminous(value=641) + source1.set_flux_luminous().value = 641 source1.commit() + assert source1.set_flux_luminous().value == 641 assert source1.source_template_link.get().rayfile.HasField("luminous_flux") assert source1.source_template_link.get().rayfile.luminous_flux.luminous_value == 641 # radiant_flux - source1.set_flux_radiant(value=1.3) + source1.set_flux_radiant().value = 1.3 source1.commit() + assert source1.set_flux_radiant().value == 1.3 assert source1.source_template_link.get().rayfile.HasField("radiant_flux") assert source1.source_template_link.get().rayfile.radiant_flux.radiant_value == 1.3 @@ -323,7 +325,8 @@ def test_create_rayfile_source(speos: Speos): assert source1.source_template_link.get().rayfile.HasField("flux_from_ray_file") # spectrum (need to change ray file so that it does not contain spectral data) - source1.set_ray_file_uri(uri=str(Path(test_path) / "RaysWithoutSpectralData.RAY")) + source1.ray_file_uri = Path(test_path) / "RaysWithoutSpectralData.RAY" + # source1.set_ray_file_uri(uri=str(Path(test_path) / "RaysWithoutSpectralData.RAY")) source1.set_spectrum().set_blackbody() source1.commit() assert source1.source_template_link.get().rayfile.spectrum_guid != "" @@ -333,7 +336,7 @@ def test_create_rayfile_source(speos: Speos): # properties # axis_system - source1.set_axis_system(axis_system=[50, 40, 50, 1, 0, 0, 0, 1, 0, 0, 0, 1]) + source1.axis_system = [50, 40, 50, 1, 0, 0, 0, 1, 0, 0, 0, 1] source1.commit() assert source1._source_instance.HasField("rayfile_properties") assert source1._source_instance.rayfile_properties.axis_system == [ @@ -574,9 +577,11 @@ def test_keep_same_internal_feature(speos: Speos): # RAY FILE SOURCE source3 = SourceRayFile(project=p, name="Ray-fiile.1") - source3.set_ray_file_uri( - uri=str(Path(test_path) / "RaysWithoutSpectralData.RAY") - ).set_spectrum().set_blackbody() + source3.ray_file_uri = Path(test_path) / "RaysWithoutSpectralData.RAY" + source3.set_spectrum().set_blackbody() + # source3.set_ray_file_uri( + # uri=str(Path(test_path) / "RaysWithoutSpectralData.RAY") + # ).set_spectrum().set_blackbody() source3.commit() spectrum_guid = source3.source_template_link.get().rayfile.spectrum_guid @@ -596,7 +601,7 @@ def test_commit_source(speos: Speos): # Create source1 = SourceRayFile(project=p, name="Ray-file.1") - source1.set_ray_file_uri(uri=str(Path(test_path) / "Rays.ray")) + source1.ray_file_uri = Path(test_path) / "Rays.ray" assert source1.source_template_link is None assert len(p.scene_link.get().sources) == 0 @@ -608,7 +613,7 @@ def test_commit_source(speos: Speos): assert p.scene_link.get().sources[0] == source1._source_instance # Change only in local isn't committed - source1.set_axis_system(axis_system=[10, 10, 10, 1, 0, 0, 0, 1, 0, 0, 0, 1]) + source1.axis_system = [10, 10, 10, 1, 0, 0, 0, 1, 0, 0, 0, 1] assert p.scene_link.get().sources[0] != source1._source_instance source1.delete() @@ -620,7 +625,8 @@ def test_reset_source(speos: Speos): # Create + commit source1 = SourceRayFile(project=p, name="1") - source1.set_ray_file_uri(uri=str(Path(test_path) / "Rays.ray")) + source1.ray_file_uri = Path(test_path) / "Rays.ray" + # source1.set_ray_file_uri(uri=str(Path(test_path) / "Rays.ray")) source1.commit() assert source1.source_template_link is not None assert source1.source_template_link.get().HasField("rayfile") @@ -628,7 +634,7 @@ def test_reset_source(speos: Speos): assert p.scene_link.get().sources[0].HasField("rayfile_properties") # Change local data (on template and on instance) - source1.set_flux_radiant(value=3.5) # template + source1.set_flux_radiant().value = 3.5 # template source1.set_exit_geometries( exit_geometries=[GeoRef.from_native_link("TheBodyB/TheFaceB1")] ) # instance @@ -716,9 +722,9 @@ def test_rayfile_modify_after_reset(speos: Speos): # Create + commit source = SourceRayFile(project=p, name="1") - source.set_flux_luminous().set_ray_file_uri( - uri=str(Path(test_path) / "RaysWithoutSpectralData.RAY") - ).set_spectrum() + source.set_flux_luminous() + source.ray_file_uri = Path(test_path) / "RaysWithoutSpectralData.RAY" + source.set_spectrum() source.commit() # Ask for reset @@ -727,7 +733,7 @@ def test_rayfile_modify_after_reset(speos: Speos): # Modify after a reset # Template assert source._source_template.rayfile.luminous_flux.luminous_value == 683 - source.set_flux_luminous(value=500) + source.set_flux_luminous().value = 500 assert source._source_template.rayfile.luminous_flux.luminous_value == 500 # Intermediate class for spectrum @@ -750,7 +756,7 @@ def test_rayfile_modify_after_reset(speos: Speos): 0, 1, ] - source.set_axis_system([50, 20, 10, 1, 0, 0, 0, 1, 0, 0, 0, 1]) + source.axis_system = [50, 20, 10, 1, 0, 0, 0, 1, 0, 0, 0, 1] assert source._source_instance.rayfile_properties.axis_system == [ 50, 20, @@ -833,9 +839,9 @@ def test_delete_source(speos: Speos): p = Project(speos=speos) # Create + commit - # source1 = p.create_source(name="1") - source1 = SourceRayFile(project=p, name="1") - source1.set_ray_file_uri(uri=str(Path(test_path) / "Rays.ray")) + source1 = p.create_source(name="1", feature_type=SourceRayFile) + # source1 = SourceRayFile(project=p, name="1") + source1.ray_file_uri = Path(test_path) / "Rays.ray" source1.commit() assert source1.source_template_link.get().HasField("rayfile") assert source1._source_template.HasField("rayfile") # local @@ -889,7 +895,8 @@ def test_print_source(speos: Speos): # Create + commit # source = p.create_source(name="1") source = SourceRayFile(project=p, name="1") - source.set_ray_file_uri(uri=str(Path(test_path) / "RaysWithoutSpectralData.RAY")).set_spectrum() + source.ray_file_uri = Path(test_path) / "RaysWithoutSpectralData.RAY" + source.set_spectrum() source.commit() # Retrieve print From 75cbaea1f143e92ea11c5bf35a5f79c75b148019 Mon Sep 17 00:00:00 2001 From: plu Date: Wed, 6 Aug 2025 11:30:13 +0100 Subject: [PATCH 11/52] refactor the surface source class --- src/ansys/speos/core/generic/constants.py | 5 + src/ansys/speos/core/source.py | 377 ++++++++++++++++------ 2 files changed, 291 insertions(+), 91 deletions(-) diff --git a/src/ansys/speos/core/generic/constants.py b/src/ansys/speos/core/generic/constants.py index d748f59a9..7b76e2d90 100644 --- a/src/ansys/speos/core/generic/constants.py +++ b/src/ansys/speos/core/generic/constants.py @@ -67,6 +67,11 @@ class RADIANT: VALUE = 1 + class INTENSITY: + """Constant class for Intensity.""" + + VALUE = 5 + class SENSOR: """Constant class for Sensors.""" diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index 1efe7d862..8d089ce21 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -1091,6 +1091,151 @@ class SourceSurface(BaseSource): Uses default values when True. """ + class Intensity: + """Intensity type of flux. + + By default, Intensity flux value is set to be 5 cd. + + Parameters + ---------- + intensity_flux : ansys.api.speos.source.v1.source_pb2.LuminousIntensity + LuminousIntensity protobuf object to modify. + default_values : bool + Uses default values when True. + stable_ctr : bool + Variable to indicate if usage is inside class scope + + Notes + ----- + **Do not instantiate this class yourself**, use set_flux_luminous_intensity + method available in Source classes. + """ + + def __init__( + self, + intensity_flux: source_pb2.LuminousIntensity, + default_values: bool = True, + stable_ctr: bool = False, + ): + if not stable_ctr: + msg = "Intensity class instantiated outside of class scope" + raise RuntimeError(msg) + self._intensity_flux = intensity_flux + + if default_values: + self.value = SOURCE.INTENSITY.VALUE + + @property + def value(self) -> float: + """Get intensity flux value. + + Returns + ------- + float + Intensity flux value. + + """ + return self._intensity_flux.luminous_intensity_value + + @value.setter + def value(self, value: float) -> None: + """Set intensity flux value. + + Parameters + ---------- + value: float + Intensity flux value. + + Returns + ------- + None + + """ + self._intensity_flux.luminous_intensity_value = value + + class ExitanceConstant: + """Type of surface source existence : existence constant. + + Parameters + ---------- + exitance_constant : ansys.api.speos.source.v1.source_pb2.SourceTemplate.Surface. + ExitanceConstant + Existence constant to complete. + exitance_constant_props : ansys.api.speos.scene.v2.scene_pb2.Scene.SourceInstance. + SurfaceProperties.ExitanceConstantProperties + Existence constant properties to complete. + default_values : bool + Uses default values when True. + stable_ctr : bool + Variable to indicate if usage is inside class scope + + Notes + ----- + **Do not instantiate this class yourself**, use set_exitance_constant method + available in Source classes. + """ + + def __init__( + self, + exitance_constant, + exitance_constant_props, + default_values: bool = True, + stable_ctr: bool = False, + ): + if not stable_ctr: + msg = "ExitanceConstant class instantiated outside of class scope" + raise RuntimeError(msg) + self._exitance_constant = exitance_constant + self._exitance_constant_props = exitance_constant_props + if default_values: + self.geometries = [] + + @property + def geometries(self) -> List[tuple[GeoRef, bool]]: + """Get geometries linked to surface source. + + Returns + ------- + List[tuple[GeoRef, bool]] + list of tuple which contains geometry ref and bool for normal direction. + + """ + return self._exitance_constant_props.geo_paths + + @geometries.setter + def geometries(self, geometries: List[tuple[Union[GeoRef, face.Face, body.Body], bool]]): + """Set geometries linked to surface source. + + Parameters + ---------- + geometries: List[tuple[GeoRef, bool]] + list of tuple which contains geometry ref and bool for normal direction. + + Returns + ------- + None + + """ + geo_paths = [] + for gr, reverse_normal in geometries: + if isinstance(gr, GeoRef): + geo_paths.append( + ProtoScene.GeoPath( + geo_path=gr.to_native_link(), reverse_normal=reverse_normal + ) + ) + elif isinstance(gr, (face.Face, body.Body)): + geo_paths.append( + ProtoScene.GeoPath( + geo_path=gr.geo_path.to_native_link(), reverse_normal=reverse_normal + ) + ) + else: + msg = f"Type {type(gr)} is not supported as Surface Source geometry input." + raise TypeError(msg) + self._exitance_constant_props.ClearField("geo_paths") + self._exitance_constant_props.geo_paths.extend(geo_paths) + class ExitanceVariable: """Type of surface source existence : existence variable. @@ -1129,44 +1274,65 @@ def __init__( if default_values: # Default values self._exitance_variable.SetInParent() - self.set_axis_plane() + self.axis_plane = [0, 0, 0, 1, 0, 0, 0, 1, 0] + + @property + def xmp_file_uri(self) -> str: + """Get xmp file uri. + + Returns + ------- + str + xmp file uri. - def set_xmp_file_uri(self, uri: str) -> SourceSurface.ExitanceVariable: - """Set existence xmp file. + """ + return self._exitance_variable.exitance_xmp_file_uri + + @xmp_file_uri.setter + def xmp_file_uri(self, xmp_file_uri: Union[str, Path]) -> None: + """Set xmp file uri. Parameters ---------- - uri : str - XMP file describing existence. + xmp_file_uri: Union[str, Path] + xmp file uri. Returns ------- - ansys.speos.core.source.SourceSurface.ExitanceVariable - ExitanceVariable of surface source. + None + """ - self._exitance_variable.exitance_xmp_file_uri = uri - return self + self._exitance_variable.exitance_xmp_file_uri = str(xmp_file_uri) + + @property + def axis_plane(self) -> List[float]: + """Get axis plane. + + Returns + ------- + List[float] + Position of the existence map [Ox Oy Oz Xx Xy Xz Yx Yy Yz]. + By default, ``[0, 0, 0, 1, 0, 0, 0, 1, 0]``. + + """ + return self._exitance_variable_props.axis_plane - def set_axis_plane( - self, axis_plane: Optional[List[float]] = None - ) -> SourceSurface.ExitanceVariable: - """Set position of the existence map. + @axis_plane.setter + def axis_plane(self, axis_plane: List[float]) -> None: + """Set axis plane. Parameters ---------- - axis_plane : Optional[List[float]] + axis_plane: List[float] Position of the existence map [Ox Oy Oz Xx Xy Xz Yx Yy Yz]. By default, ``[0, 0, 0, 1, 0, 0, 0, 1, 0]``. Returns ------- - ansys.speos.core.source.SourceSurface.ExitanceVariable - ExitanceVariable of surface Source. + None + """ - if axis_plane is None: - axis_plane = [0, 0, 0, 1, 0, 0, 0, 1, 0] self._exitance_variable_props.axis_plane[:] = axis_plane - return self @general_methods.min_speos_version(25, 2, 0) def __init__( @@ -1210,10 +1376,14 @@ def __init__( # Attribute gathering more complex existence type self._exitance_type = None + # Attribute gathering more complex flux type + self._flux_type = None if default_values: # Default values - self.set_flux_luminous().set_exitance_constant(geometries=[]).set_intensity() + self.set_flux_luminous() + self.set_exitance_constant().geometries = [] + self.set_intensity() self.set_spectrum() @property @@ -1269,56 +1439,88 @@ def set_flux_from_intensity_file(self) -> SourceSurface: self._source_template.surface.flux_from_intensity_file.SetInParent() return self - def set_flux_luminous(self, value: float = 683) -> SourceSurface: + def set_flux_luminous(self) -> SourceSurface.Luminous: """Set luminous flux. - Parameters - ---------- - value : float - Luminous flux in lumens. - By default, ``683.0``. - Returns ------- - ansys.speos.core.source.SourceSurface - Surface source. + ansys.speos.core.source.SourceSurface.Luminous + Luminous flux type source. """ - self._source_template.surface.luminous_flux.luminous_value = value - return self + if self._flux_type is None and self._source_template.surface.HasField("luminous_flux"): + self._flux_type = SourceSurface.Luminous( + luminous_flux=self._source_template.surface.luminous_flux, + default_values=False, + stable_ctr=True, + ) + elif not isinstance(self._flux_type, SourceSurface.Luminous): + self._flux_type = SourceSurface.Luminous( + luminous_flux=self._source_template.surface.luminous_flux, + default_values=True, + stable_ctr=True, + ) + elif self._flux_type._luminous_flux is not self._source_template.surface.luminous_flux: + self._flux_type._luminous_flux = self._source_template.surface.luminous_flux + return self._flux_type + # self._source_template.surface.luminous_flux.luminous_value = value + # return self - def set_flux_radiant(self, value: float = 1) -> SourceSurface: + def set_flux_radiant(self) -> SourceSurface.Radiant: """Set radiant flux. - Parameters - ---------- - value : float - Radiant flux in watts. - By default, ``1.0``. - Returns ------- - ansys.speos.core.source.SourceSurface - Surface source. + ansys.speos.core.source.SourceSurface.Radiant + Radiant flux type source. """ - self._source_template.surface.radiant_flux.radiant_value = value - return self - - def set_flux_luminous_intensity(self, value: float = 5) -> SourceSurface: - """Set luminous intensity flux. + if self._flux_type is None and self._source_template.surface.HasField("radiant_flux"): + self._flux_type = SourceSurface.Radiant( + radiant_flux=self._source_template.surface.radiant_flux, + default_values=False, + stable_ctr=True, + ) + elif not isinstance(self._flux_type, SourceSurface.Radiant): + self._flux_type = SourceSurface.Radiant( + radiant_flux=self._source_template.surface.radiant_flux, + default_values=True, + stable_ctr=True, + ) + elif self._flux_type._radiant_flux is not self._source_template.surface.radiant_flux: + self._flux_type._radiant_flux = self._source_template.surface.radiant_flux + return self._flux_type + # self._source_template.surface.radiant_flux.radiant_value = value + # return self - Parameters - ---------- - value : float - Luminous intensity in candelas. - By default, ``5.0``. + def set_flux_luminous_intensity(self) -> SourceSurface.Intensity: + """Set intensity flux. Returns ------- - ansys.speos.core.source.SourceSurface - Surface source. + ansys.speos.core.source.SourceSurface.Intensity + Intensity flux type source. """ - self._source_template.surface.luminous_intensity_flux.luminous_intensity_value = value - return self + if self._flux_type is None and self._source_template.surface.HasField( + "luminous_intensity_flux" + ): + self._flux_type = SourceSurface.Intensity( + intensity_flux=self._source_template.surface.luminous_intensity_flux, + default_values=False, + stable_ctr=True, + ) + elif not isinstance(self._flux_type, SourceSurface.Intensity): + self._flux_type = SourceSurface.Intensity( + intensity_flux=self._source_template.surface.luminous_intensity_flux, + default_values=True, + stable_ctr=True, + ) + elif ( + self._flux_type._intensity_flux + is not self._source_template.surface.luminous_intensity_flux + ): + self._flux_type._intensity_flux = self._source_template.surface.luminous_intensity_flux + return self._flux_type + # self._source_template.surface.luminous_intensity_flux.luminous_intensity_value = value + # return self def set_intensity(self) -> Intensity: """Set intensity. @@ -1339,49 +1541,42 @@ def set_intensity(self) -> Intensity: return self._intensity - def set_exitance_constant( - self, geometries: List[tuple[Union[GeoRef, face.Face, body.Body], bool]] - ) -> SourceSurface: + def set_exitance_constant(self) -> SourceSurface.ExitanceConstant: """Set existence constant. - Parameters - ---------- - geometries : List[tuple[ansys.speos.core.geo_ref.GeoRef, bool]] - List of (face, reverseNormal). - Returns ------- - ansys.speos.core.source.SourceSurface - Surface source. + ansys.speos.core.source.SourceSurface.ExitanceConstant + ExitanceConstant of surface source. """ - self._exitance_type = None - - self._source_template.surface.exitance_constant.SetInParent() - self._source_instance.surface_properties.exitance_constant_properties.ClearField( - "geo_paths" - ) - if geometries != []: - geo_paths = [] - for gr, reverse_normal in geometries: - if isinstance(gr, GeoRef): - geo_paths.append( - ProtoScene.GeoPath( - geo_path=gr.to_native_link(), reverse_normal=reverse_normal - ) - ) - elif isinstance(gr, (face.Face, body.Body)): - geo_paths.append( - ProtoScene.GeoPath( - geo_path=gr.geo_path.to_native_link(), reverse_normal=reverse_normal - ) - ) - else: - msg = f"Type {type(gr)} is not supported as Surface Source geometry input." - raise TypeError(msg) - self._source_instance.surface_properties.exitance_constant_properties.geo_paths.extend( - geo_paths + if self._exitance_type is None and self._source_template.surface.HasField( + "exitance_constant" + ): + # Happens in case of project created via load of speos file + self._exitance_type = SourceSurface.ExitanceConstant( + exitance_constant=self._source_template.surface.exitance_constant, + exitance_constant_props=self._source_instance.surface_properties.exitance_constant_properties, + default_values=False, + stable_ctr=True, ) - return self + elif not isinstance(self._exitance_type, SourceSurface.ExitanceConstant): + # if the _exitance_type is not ExitanceConstant then we create a new type. + self._source_template.surface.exitance_constant.SetInParent() + self._exitance_type = SourceSurface.ExitanceConstant( + exitance_constant=self._source_template.surface.exitance_constant, + exitance_constant_props=self._source_instance.surface_properties.exitance_constant_properties, + stable_ctr=True, + ) + elif ( + self._exitance_type._exitance_constant + is not self._source_template.surface.exitance_constant + ): + # Happens in case of feature reset (to be sure to always modify correct data) + self._exitance_type._exitance_constant = self._source_template.surface.exitance_constant + self._exitance_type.__exitance_constant_props = ( + self._source_instance.surface_properties.exitance_constant_properties + ) + return self._exitance_type def set_exitance_variable(self) -> SourceSurface.ExitanceVariable: """Set existence variable, taken from XMP map. From a644db0ec8cf0ab99deb693e3efae32a04d8a390 Mon Sep 17 00:00:00 2001 From: plu Date: Wed, 6 Aug 2025 11:30:42 +0100 Subject: [PATCH 12/52] update the source test and example --- examples/core/source.py | 10 ++++----- tests/core/test_source.py | 43 +++++++++++++++++++-------------------- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/examples/core/source.py b/examples/core/source.py index 08c72dec9..e42e6ed72 100644 --- a/examples/core/source.py +++ b/examples/core/source.py @@ -198,12 +198,10 @@ def create_face(body): # + 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.set_exitance_constant().geometries = [ + (GeoRef.from_native_link("TheBodyB/TheFaceF"), False), + (GeoRef.from_native_link("TheBodyC/TheFaceF"), True), +] source4.commit() print(source4) # - diff --git a/tests/core/test_source.py b/tests/core/test_source.py index 444ba5b29..ab069421a 100644 --- a/tests/core/test_source.py +++ b/tests/core/test_source.py @@ -154,8 +154,7 @@ def test_create_surface_source(speos: Speos): # Default value # source1 = p.create_source(name="Surface.1") source1 = SourceSurface(project=p, name="Surface.1") - source1.set_exitance_constant(geometries=[(GeoRef.from_native_link("BodyB"), False)]) - # source1.set_surface() + source1.set_exitance_constant().geometries = [(GeoRef.from_native_link("BodyB"), False)] source1.commit() assert source1.source_template_link is not None assert source1.source_template_link.get().HasField("surface") @@ -186,19 +185,19 @@ def test_create_surface_source(speos: Speos): assert surface_properties.intensity_properties.library_properties.HasField("axis_system") # luminous_flux - source1.set_flux_luminous(value=630) + source1.set_flux_luminous().value = 630 source1.commit() assert source1.source_template_link.get().surface.HasField("luminous_flux") assert source1.source_template_link.get().surface.luminous_flux.luminous_value == 630 # radiant_flux - source1.set_flux_radiant(value=1.1) + source1.set_flux_radiant().value = 1.1 source1.commit() assert source1.source_template_link.get().surface.HasField("radiant_flux") assert source1.source_template_link.get().surface.radiant_flux.radiant_value == 1.1 # luminous_intensity_flux - source1.set_flux_luminous_intensity(value=5.5) + source1.set_flux_luminous_intensity().value = 5.5 source1.commit() assert source1.source_template_link.get().surface.HasField("luminous_intensity_flux") assert ( @@ -207,8 +206,8 @@ def test_create_surface_source(speos: Speos): ) # exitance_variable + spectrum_from_xmp_file - source1.set_exitance_variable().set_xmp_file_uri( - uri=str(Path(test_path) / "PROJECT.Direct-no-Ray.Irradiance Ray Spectral.xmp") + source1.set_exitance_variable().xmp_file_uri = ( + Path(test_path) / "PROJECT.Direct-no-Ray.Irradiance Ray Spectral.xmp" ) source1.set_spectrum_from_xmp_file() source1.commit() @@ -230,7 +229,7 @@ def test_create_surface_source(speos: Speos): # Properties # exitance_variable axis_plane - source1.set_exitance_variable().set_axis_plane(axis_plane=[10, 10, 15, 1, 0, 0, 0, 1, 0]) + source1.set_exitance_variable().axis_plane = [10, 10, 15, 1, 0, 0, 0, 1, 0] source1.commit() assert surface_properties.HasField("exitance_variable_properties") assert surface_properties.exitance_variable_properties.axis_plane == [ @@ -246,12 +245,11 @@ def test_create_surface_source(speos: Speos): ] # exitance_constant geometries - source1.set_exitance_constant( - geometries=[ - (GeoRef.from_native_link("BodyB/FaceB1"), False), - (GeoRef.from_native_link("BodyB/FaceB2"), True), - ] - ).set_spectrum().set_blackbody() + source1.set_exitance_constant().geometries = [ + (GeoRef.from_native_link("BodyB/FaceB1"), False), + (GeoRef.from_native_link("BodyB/FaceB2"), True), + ] + source1.set_spectrum().set_blackbody() source1.commit() assert surface_properties.HasField("exitance_constant_properties") assert len(surface_properties.exitance_constant_properties.geo_paths) == 2 @@ -260,7 +258,7 @@ def test_create_surface_source(speos: Speos): assert surface_properties.exitance_constant_properties.geo_paths[1].geo_path == "BodyB/FaceB2" assert surface_properties.exitance_constant_properties.geo_paths[1].reverse_normal is True - source1.set_exitance_constant(geometries=[]) # clear geometries + source1.set_exitance_constant().geometries = [] # clear geometries assert surface_properties.HasField("exitance_constant_properties") assert len(surface_properties.exitance_constant_properties.geo_paths) == 0 @@ -549,7 +547,7 @@ def test_keep_same_internal_feature(speos: Speos): # SURFACE SOURCE source1 = SourceSurface(project=p, name="Surface.1") - source1.set_exitance_constant(geometries=[(body_b, False)]) + source1.set_exitance_constant().geometries = [(body_b, False)] source1.commit() spectrum_guid = source1.source_template_link.get().surface.spectrum_guid intensity_guid = source1.source_template_link.get().surface.intensity_guid @@ -780,10 +778,11 @@ def test_surface_modify_after_reset(speos: Speos): p = Project(speos=speos) # Create + commit - source = SourceSurface(project=p, name="Surface.2").set_flux_luminous() + source = SourceSurface(project=p, name="Surface.2") + source.set_flux_luminous() source.set_spectrum_from_xmp_file() - source.set_exitance_variable().set_xmp_file_uri( - uri=str(Path(test_path) / "PROJECT.Direct-no-Ray.Irradiance Ray Spectral.xmp") + source.set_exitance_variable().xmp_file_uri = ( + Path(test_path) / "PROJECT.Direct-no-Ray.Irradiance Ray Spectral.xmp" ) source.commit() @@ -793,7 +792,7 @@ def test_surface_modify_after_reset(speos: Speos): # Modify after a reset # Template assert source._source_template.surface.luminous_flux.luminous_value == 683 - source.set_flux_luminous(value=500) + source.set_flux_luminous().value = 500 assert source._source_template.surface.luminous_flux.luminous_value == 500 # Intermediate class for spectrum @@ -818,7 +817,7 @@ def test_surface_modify_after_reset(speos: Speos): 1, 0, ] - source.set_exitance_variable().set_axis_plane([50, 20, 10, 1, 0, 0, 0, 1, 0]) + source.set_exitance_variable().axis_plane = [50, 20, 10, 1, 0, 0, 0, 1, 0] assert source._source_instance.surface_properties.exitance_variable_properties.axis_plane == [ 50, 20, @@ -913,7 +912,7 @@ def test_print_source(speos: Speos): # SURFACE - SPECTRUM source = SourceSurface(project=p, name="Surface.1") - source.set_exitance_constant(geometries=[(GeoRef.from_native_link("BodyB"), False)]) + source.set_exitance_constant().geometries = [(GeoRef.from_native_link("BodyB"), False)] source.commit() # Retrieve print From 0fab2d4cd17e2bfe0b193886a61346529eb83536 Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Wed, 6 Aug 2025 10:34:40 +0000 Subject: [PATCH 13/52] chore: adding changelog file 690.added.md [dependabot-skip] --- doc/changelog.d/690.added.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changelog.d/690.added.md diff --git a/doc/changelog.d/690.added.md b/doc/changelog.d/690.added.md new file mode 100644 index 000000000..fcf3ce47f --- /dev/null +++ b/doc/changelog.d/690.added.md @@ -0,0 +1 @@ +Refactor source class \ No newline at end of file From f6367771caba2b328075f2c092c7c409aeab0b58 Mon Sep 17 00:00:00 2001 From: plu Date: Wed, 6 Aug 2025 12:16:50 +0100 Subject: [PATCH 14/52] fix issue and change default mono spectrum value --- src/ansys/speos/core/generic/constants.py | 2 +- src/ansys/speos/core/spectrum.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ansys/speos/core/generic/constants.py b/src/ansys/speos/core/generic/constants.py index 3bd56c7c9..19cea4017 100644 --- a/src/ansys/speos/core/generic/constants.py +++ b/src/ansys/speos/core/generic/constants.py @@ -46,7 +46,7 @@ class SPECTRUM: class MONOCHROMATIC: """Constant class for Monochromatic.""" - WAVELENGTH = 550 + WAVELENGTH = 555 class BLACKBODY: """Constant class for BlackBody.""" diff --git a/src/ansys/speos/core/spectrum.py b/src/ansys/speos/core/spectrum.py index e036e16fc..61383a57e 100644 --- a/src/ansys/speos/core/spectrum.py +++ b/src/ansys/speos/core/spectrum.py @@ -243,7 +243,7 @@ def wavelengths(self, wavelengths: list[float]) -> None: None """ - self._sampled.wavelengths = wavelengths + self._sampled.wavelengths[:] = wavelengths @property def values(self) -> List[float]: From da67f35657b99a89ae9563b32f78bc3b6b8cf34a Mon Sep 17 00:00:00 2001 From: plu Date: Wed, 6 Aug 2025 12:19:42 +0100 Subject: [PATCH 15/52] update other tests based on the new refactor methods from source.py --- tests/core/test_project.py | 18 ++++++------ tests/core/test_proto_message_utils.py | 10 +++---- tests/core/test_sensor.py | 6 ++-- tests/core/test_simulation.py | 15 +++++----- tests/core/test_spectrum.py | 39 +++++++++++++++++--------- 5 files changed, 51 insertions(+), 37 deletions(-) diff --git a/tests/core/test_project.py b/tests/core/test_project.py index 555950a0d..f270bf780 100644 --- a/tests/core/test_project.py +++ b/tests/core/test_project.py @@ -40,7 +40,7 @@ def test_find_feature(speos: Speos): # Create a luminaire source in the project source1 = p.create_source(name="Source.1", feature_type=SourceLuminaire) - source1.set_intensity_file_uri(uri=str(Path(test_path) / "IES_C_DETECTOR.ies")) + source1.intensity_file_uri = Path(test_path) / "IES_C_DETECTOR.ies" assert len(p._features) == 1 source1.commit() assert len(p.scene_link.get().sources) == 1 @@ -298,7 +298,7 @@ def test_delete(speos: Speos): # Create a surface source in the project source1 = p.create_source(name="Source.1", feature_type=SourceLuminaire) - source1.set_intensity_file_uri(uri=str(Path(test_path) / "IES_C_DETECTOR.ies")) + source1.intensity_file_uri = Path(test_path) / "IES_C_DETECTOR.ies" assert len(p._features) == 1 source1.commit() assert len(p.scene_link.get().sources) == 1 @@ -355,7 +355,7 @@ def test_from_file(speos: Speos): assert type(feat_ssrs[0]) is SensorIrradiance # And that we can modify it (and that other values are not overridden by default values) - feat_ssrs[0].set_type_colorimetric().set_wavelengths_range().set_end(value=800) + feat_ssrs[0].set_type_colorimetric().set_wavelengths_range().end = 800 feat_ssrs[0].commit() ssr_link = speos.client[p.scene_link.get().sensors[0].sensor_guid] ssr_data = ssr_link.get() @@ -472,7 +472,7 @@ def test_preview_visual_data(speos: Speos): # preview luminaire source # preview when there is cad sr = p2.create_source(name="Luminaire_source", feature_type=SourceLuminaire) - sr.set_intensity_file_uri(uri=str(Path(test_path) / "IES_C_DETECTOR.ies")) + sr.intensity_file_uri = Path(test_path) / "IES_C_DETECTOR.ies" sr.set_spectrum().set_halogen() sr.commit() p2.preview() @@ -480,13 +480,13 @@ def test_preview_visual_data(speos: Speos): p3 = Project(speos=speos) p3.create_root_part().commit() # Needed for 251 server. sr = p3.create_source(name="Luminaire_source.2", feature_type=SourceLuminaire) - sr.set_intensity_file_uri(uri=str(Path(test_path) / "IES_C_DETECTOR.ies")) + sr.intensity_file_uri = Path(test_path) / "IES_C_DETECTOR.ies" sr.commit() p3.preview() # preview rayfile source sr = p2.create_source(name="Rayfile_source", feature_type=SourceRayFile) - sr.set_ray_file_uri(uri=str(Path(test_path) / "Rays.ray")) + sr.ray_file_uri = Path(test_path) / "Rays.ray" sr.commit() p2.preview() @@ -500,13 +500,13 @@ def test_preview_visual_data(speos: Speos): ).set_normals([0, 0, 1, 0, 0, 1, 0, 0, 1]).commit() sr = p2.create_source(name="Surface.1", feature_type=SourceSurface) - sr.set_exitance_constant(geometries=[(GeoRef.from_native_link("TheBodyB/TheFaceF"), False)]) + sr.set_exitance_constant().geometries = [(GeoRef.from_native_link("TheBodyB/TheFaceF"), False)] sr.commit() p2.preview() # variable exitance sr.set_spectrum_from_xmp_file() - sr.set_exitance_variable().set_xmp_file_uri( - uri=str(Path(test_path) / "PROJECT.Direct-no-Ray.Irradiance Ray Spectral.xmp") + sr.set_exitance_variable().xmp_file_uri = ( + Path(test_path) / "PROJECT.Direct-no-Ray.Irradiance Ray Spectral.xmp" ) sr.commit() p2.preview() diff --git a/tests/core/test_proto_message_utils.py b/tests/core/test_proto_message_utils.py index 0c4a459b7..40142a175 100644 --- a/tests/core/test_proto_message_utils.py +++ b/tests/core/test_proto_message_utils.py @@ -48,7 +48,7 @@ def test_replace_guid_elt(speos: Speos): root_part.commit() src_feat = SourceSurface(project=p, name="Surface.1") - src_feat.set_exitance_constant(geometries=[(GeoRef.from_native_link("BodyB"), False)]) + src_feat.set_exitance_constant().geometries = [(GeoRef.from_native_link("BodyB"), False)] src_feat.commit() # Retrieve source template message and transform it into dict @@ -97,7 +97,7 @@ def test_replace_guid_elt_ignore_simple_key(speos: Speos): root_part.commit() src_feat = SourceSurface(project=p, name="Surface.1") - src_feat.set_exitance_constant(geometries=[(GeoRef.from_native_link("BodyB"), False)]) + src_feat.set_exitance_constant().geometries = [(GeoRef.from_native_link("BodyB"), False)] src_feat.commit() # Retrieve source template message and transform it into dict @@ -249,7 +249,7 @@ def test_value_finder_key_startswith(speos: Speos): root_part.commit() src_feat = SourceSurface(project=p, name="Surface.1") - src_feat.set_exitance_constant(geometries=[(GeoRef.from_native_link("BodyB"), False)]) + src_feat.set_exitance_constant().geometries = [(GeoRef.from_native_link("BodyB"), False)] src_feat.commit() # Retrieve source instance message and transform it into dict @@ -278,7 +278,7 @@ def test__value_finder_key_endswith(speos: Speos): root_part.commit() src_feat = SourceSurface(project=p, name="Surface.1") - src_feat.set_exitance_constant(geometries=[(GeoRef.from_native_link("BodyB"), False)]) + src_feat.set_exitance_constant().geometries = [(GeoRef.from_native_link("BodyB"), False)] src_feat.commit() # Retrieve source instance message and transform it into dict @@ -311,7 +311,7 @@ def test_replace_properties(speos: Speos): root_part.commit() src_feat = SourceSurface(project=p, name="Surface.1") - src_feat.set_exitance_constant(geometries=[(GeoRef.from_native_link("BodyB"), False)]) + src_feat.set_exitance_constant().geometries = [(GeoRef.from_native_link("BodyB"), False)] src_feat.set_intensity().set_gaussian().set_axis_system([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]) src_feat.commit() diff --git a/tests/core/test_sensor.py b/tests/core/test_sensor.py index e9ec5a8c0..d175f7607 100644 --- a/tests/core/test_sensor.py +++ b/tests/core/test_sensor.py @@ -333,9 +333,9 @@ def test_create_camera_sensor(speos: Speos): assert mode_photometric.color_mode_color.HasField("balance_mode_none") # wavelengths_range - sensor1.set_mode_photometric().set_wavelengths_range().set_start(value=430).set_end( - value=750 - ).set_sampling(value=15) + sensor1.set_mode_photometric().set_wavelengths_range().start = 430 + sensor1.set_mode_photometric().set_wavelengths_range().end = 750 + sensor1.set_mode_photometric().set_wavelengths_range().sampling = 15 sensor1.commit() camera_sensor_template = sensor1.sensor_template_link.get().camera_sensor_template mode_photometric = camera_sensor_template.sensor_mode_photometric diff --git a/tests/core/test_simulation.py b/tests/core/test_simulation.py index e8122a744..d3835841e 100644 --- a/tests/core/test_simulation.py +++ b/tests/core/test_simulation.py @@ -391,7 +391,7 @@ def test_commit(speos: Speos): ssr2.commit() src = p.create_source(name="Luminaire.1", feature_type=SourceLuminaire) - src.set_intensity_file_uri(uri=str(Path(test_path) / "IES_C_DETECTOR.ies")) + src.intensity_file_uri = Path(test_path) / "IES_C_DETECTOR.ies" src.commit() # Create @@ -445,7 +445,7 @@ def test_reset(speos: Speos): ssr2.commit() src = p.create_source(name="Luminaire.1", feature_type=SourceLuminaire) - src.set_intensity_file_uri(uri=str(Path(test_path) / "IES_C_DETECTOR.ies")) + src.intensity_file_uri = Path(test_path) / "IES_C_DETECTOR.ies" src.commit() # Create + commit @@ -499,7 +499,7 @@ def test_direct_modify_after_reset(speos: Speos): ssr2.commit() src = p.create_source(name="Luminaire.1", feature_type=SourceLuminaire) - src.set_intensity_file_uri(uri=str(Path(test_path) / "IES_C_DETECTOR.ies")) + src.intensity_file_uri = Path(test_path) / "IES_C_DETECTOR.ies" src.commit() # Create + commit @@ -569,7 +569,7 @@ def test_inverse_modify_after_reset(speos: Speos): ssr2.commit() src = p.create_source(name="Luminaire.1", feature_type=SourceLuminaire) - src.set_intensity_file_uri(uri=str(Path(test_path) / "IES_C_DETECTOR.ies")) + src.intensity_file_uri = Path(test_path) / "IES_C_DETECTOR.ies" src.commit() # Create + commit @@ -645,7 +645,7 @@ def test_interactive_modify_after_reset(speos: Speos): ssr2.commit() src = p.create_source(name="Luminaire.1", feature_type=SourceLuminaire) - src.set_intensity_file_uri(uri=str(Path(test_path) / "IES_C_DETECTOR.ies")) + src.intensity_file_uri = Path(test_path) / "IES_C_DETECTOR.ies" src.commit() # Create + commit @@ -697,7 +697,7 @@ def test_delete(speos: Speos): ssr.commit() src = p.create_source(name="Luminaire.1", feature_type=SourceLuminaire) - src.set_intensity_file_uri(uri=str(Path(test_path) / "IES_C_DETECTOR.ies")) + src.intensity_file_uri = Path(test_path) / "IES_C_DETECTOR.ies" src.commit() # Create + commit @@ -1032,7 +1032,8 @@ def test_export_vtp(speos: Speos): ) sim = p5.find(name=".*", name_regex=True, feature_type=SimulationDirect)[0] sensor_irra = p5.find(name=".*", name_regex=True, feature_type=SensorIrradiance)[0] - sensor_irra.set_dimensions().set_x_sampling(10).set_y_sampling(10) + sensor_irra.set_dimensions().x_sampling = 10 + sensor_irra.set_dimensions().x_sampling = 10 sensor_irra.set_type_photometric() sensor_irra.commit() speos_results, vtp_results = sim.compute_CPU(export_vtp=True) diff --git a/tests/core/test_spectrum.py b/tests/core/test_spectrum.py index 1659b7faf..994e87b93 100644 --- a/tests/core/test_spectrum.py +++ b/tests/core/test_spectrum.py @@ -37,17 +37,21 @@ def test_create_spectrum(speos: Speos): assert spectrum1.spectrum_link.get().monochromatic.wavelength == 555 # monochromatic - spectrum1.set_monochromatic(wavelength=777).commit() + spectrum1.set_monochromatic().wavelength = 777 + spectrum1.commit() assert spectrum1.spectrum_link.get().HasField("monochromatic") assert spectrum1.spectrum_link.get().monochromatic.wavelength == 777 # blackbody - spectrum1.set_blackbody(temperature=3000).commit() + spectrum1.set_blackbody().temperature = 3000 + spectrum1.commit() assert spectrum1.spectrum_link.get().HasField("blackbody") assert spectrum1.spectrum_link.get().blackbody.temperature == 3000 # sampled - spectrum1.set_sampled(wavelengths=[300, 400, 500], values=[30, 20, 70]).commit() + spectrum1.set_sampled().wavelengths = [300, 400, 500] + spectrum1.set_sampled().values = [30, 20, 70] + spectrum1.commit() assert spectrum1.spectrum_link.get().HasField("sampled") assert spectrum1.spectrum_link.get().sampled.wavelengths == [300, 400, 500] assert spectrum1.spectrum_link.get().sampled.values == [30, 20, 70] @@ -59,31 +63,38 @@ def test_create_spectrum(speos: Speos): assert spectrum1.spectrum_link.get().HasField("library") # predefined - spectrum1.set_incandescent().commit() + spectrum1.set_incandescent() + spectrum1.commit() assert spectrum1.spectrum_link.get().HasField("predefined") assert spectrum1.spectrum_link.get().predefined.HasField("incandescent") - spectrum1.set_warmwhitefluorescent().commit() + spectrum1.set_warmwhitefluorescent() + spectrum1.commit() assert spectrum1.spectrum_link.get().HasField("predefined") assert spectrum1.spectrum_link.get().predefined.HasField("warmwhitefluorescent") - spectrum1.set_daylightfluorescent().commit() + spectrum1.set_daylightfluorescent() + spectrum1.commit() assert spectrum1.spectrum_link.get().HasField("predefined") assert spectrum1.spectrum_link.get().predefined.HasField("daylightfluorescent") - spectrum1.set_white_led().commit() + spectrum1.set_white_led() + spectrum1.commit() assert spectrum1.spectrum_link.get().HasField("predefined") assert spectrum1.spectrum_link.get().predefined.HasField("whiteLED") - spectrum1.set_halogen().commit() + spectrum1.set_halogen() + spectrum1.commit() assert spectrum1.spectrum_link.get().HasField("predefined") assert spectrum1.spectrum_link.get().predefined.HasField("halogen") - spectrum1.set_metalhalide().commit() + spectrum1.set_metalhalide() + spectrum1.commit() assert spectrum1.spectrum_link.get().HasField("predefined") assert spectrum1.spectrum_link.get().predefined.HasField("metalhalide") - spectrum1.set_highpressuresodium().commit() + spectrum1.set_highpressuresodium() + spectrum1.commit() assert spectrum1.spectrum_link.get().HasField("predefined") assert spectrum1.spectrum_link.get().predefined.HasField("highpressuresodium") @@ -94,7 +105,7 @@ def test_commit_spectrum(speos: Speos): """Test commit of spectrum.""" # Create spectrum1 = Spectrum(speos_client=speos.client, name="Spectrum.1") - spectrum1.set_monochromatic(wavelength=777) + spectrum1.set_monochromatic().wavelength = 777 assert spectrum1.spectrum_link is None # Commit @@ -109,7 +120,8 @@ def test_reset_spectrum(speos: Speos): """Test reset of spectrum.""" # Create + commit spectrum1 = Spectrum(speos_client=speos.client, name="Spectrum.1") - spectrum1.set_monochromatic(wavelength=777).commit() + spectrum1.set_monochromatic().wavelength = 777 + spectrum1.commit() assert spectrum1.spectrum_link.get().HasField("monochromatic") # Change local data @@ -129,7 +141,8 @@ def test_delete_spectrum(speos: Speos): """Test delete of spectrum.""" # Create + commit spectrum1 = Spectrum(speos_client=speos.client, name="Spectrum.1") - spectrum1.set_monochromatic(wavelength=777).commit() + spectrum1.set_monochromatic().wavelength = 777 + spectrum1.commit() assert spectrum1.spectrum_link.get().HasField("monochromatic") assert spectrum1._spectrum.HasField("monochromatic") From fef8ac7689034683c8d6d39903d80aa0f758cda3 Mon Sep 17 00:00:00 2001 From: plu Date: Wed, 6 Aug 2025 12:42:48 +0100 Subject: [PATCH 16/52] fix visual data issue --- src/ansys/speos/core/source.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index 8d089ce21..14266bd9b 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -1402,7 +1402,9 @@ def visual_data(self) -> _VisualData: self._visual_data = ( _VisualData( ray=True, - coordinate_system=True if self._exitance_type is not None else False, + coordinate_system=True + if isinstance(self._exitance_type, SourceSurface.ExitanceVariable) + else False, ) if general_methods._GRAPHICS_AVAILABLE else None From 2a5bf45a6b1b7f72445af9d2d87634c97001e701 Mon Sep 17 00:00:00 2001 From: plu Date: Wed, 6 Aug 2025 12:45:36 +0100 Subject: [PATCH 17/52] update other examples related to source refactor methods --- examples/core/project.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/core/project.py b/examples/core/project.py index 4575b887c..7a0a298a7 100644 --- a/examples/core/project.py +++ b/examples/core/project.py @@ -78,7 +78,7 @@ # #### Source 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.intensity_file_uri = assets_data_path / "IES_C_DETECTOR.ies" source1.commit() @@ -193,7 +193,7 @@ # modify the surface source, e.g. surface source wavelength: -src.set_spectrum().set_monochromatic(wavelength=550) +src.set_spectrum().set_monochromatic.wavelength = 550 src.commit() From e51350b56cf9389604434b6bedf2242eb00ff9f4 Mon Sep 17 00:00:00 2001 From: plu Date: Wed, 6 Aug 2025 13:05:49 +0100 Subject: [PATCH 18/52] fix issue in sensor test and sensor class --- src/ansys/speos/core/sensor.py | 2 +- tests/core/test_sensor.py | 66 ++++++++++++++++++---------------- 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/ansys/speos/core/sensor.py b/src/ansys/speos/core/sensor.py index d24e1ac25..9df5bbbb9 100644 --- a/src/ansys/speos/core/sensor.py +++ b/src/ansys/speos/core/sensor.py @@ -781,7 +781,7 @@ def __init__( if default_values: # Default values - self.set_sampling() + self.sampling = SENSOR.LAYERTYPES.INCIDENCE_SAMPLING @property def sampling(self) -> BaseSensor.LayerTypeIncidenceAngle: diff --git a/tests/core/test_sensor.py b/tests/core/test_sensor.py index d175f7607..b466663a6 100644 --- a/tests/core/test_sensor.py +++ b/tests/core/test_sensor.py @@ -485,9 +485,9 @@ def test_create_irradiance_sensor(speos: Speos): assert sensor_template.sensor_type_colorimetric.wavelengths_range.w_end == 700 assert sensor_template.sensor_type_colorimetric.wavelengths_range.w_sampling == 13 # chosen wavelengths range - sensor1.set_type_colorimetric().set_wavelengths_range().set_start(value=450).set_end( - value=800 - ).set_sampling(value=15) + sensor1.set_type_colorimetric().set_wavelengths_range().start = 450 + sensor1.set_type_colorimetric().set_wavelengths_range().end = 800 + sensor1.set_type_colorimetric().set_wavelengths_range().sampling = 15 sensor1.commit() sensor_template = sensor1.sensor_template_link.get().irradiance_sensor_template assert sensor_template.sensor_type_colorimetric.wavelengths_range.w_start == 450 @@ -511,9 +511,9 @@ def test_create_irradiance_sensor(speos: Speos): assert sensor_template.sensor_type_spectral.wavelengths_range.w_end == 700 assert sensor_template.sensor_type_spectral.wavelengths_range.w_sampling == 13 # chosen wavelengths range - sensor1.set_type_spectral().set_wavelengths_range().set_start(value=450).set_end( - value=800 - ).set_sampling(value=15) + sensor1.set_type_spectral().set_wavelengths_range().start = 450 + sensor1.set_type_spectral().set_wavelengths_range().end = 800 + sensor1.set_type_spectral().set_wavelengths_range().sampling = 15 sensor1.commit() sensor_template = sensor1.sensor_template_link.get().irradiance_sensor_template assert sensor_template.sensor_type_spectral.wavelengths_range.w_start == 450 @@ -560,9 +560,12 @@ def test_create_irradiance_sensor(speos: Speos): assert irra_properties.integration_direction == [] # dimensions - sensor1.set_dimensions().set_x_start(value=-10).set_x_end(value=10).set_x_sampling( - value=60 - ).set_y_start(value=-20).set_y_end(value=20).set_y_sampling(value=120) + sensor1.set_dimensions().x_start = -10.0 + sensor1.set_dimensions().x_end = 10 + sensor1.set_dimensions().x_sampling = 60 + sensor1.set_dimensions().y_start = -20 + sensor1.set_dimensions().y_end = 20 + sensor1.set_dimensions().y_sampling = 120 sensor1.commit() sensor_template = sensor1.sensor_template_link.get().irradiance_sensor_template assert sensor_template.HasField("dimensions") @@ -662,9 +665,8 @@ def test_create_irradiance_sensor(speos: Speos): ) # layer_type_sequence - sensor1.set_layer_type_sequence().set_maximum_nb_of_sequence( - value=5 - ).set_define_sequence_per_faces() + sensor1.set_layer_type_sequence().maximum_nb_of_sequence = 5 + sensor1.set_layer_type_sequence().set_define_sequence_per_faces() sensor1.commit() assert irra_properties.HasField("layer_type_sequence") assert irra_properties.layer_type_sequence.maximum_nb_of_sequence == 5 @@ -687,7 +689,7 @@ def test_create_irradiance_sensor(speos: Speos): assert irra_properties.HasField("layer_type_polarization") # layer_type_incidence_angle - sensor1.set_layer_type_incidence_angle().set_sampling(value=8) + sensor1.set_layer_type_incidence_angle().sampling = 8 sensor1.commit() assert irra_properties.HasField("layer_type_incidence_angle") assert irra_properties.layer_type_incidence_angle.sampling == 8 @@ -800,9 +802,9 @@ def test_create_radiance_sensor(speos: Speos): == 13 ) # chosen wavelengths range - sensor1.set_type_spectral().set_wavelengths_range().set_start(value=450).set_end( - value=800 - ).set_sampling(value=15) + sensor1.set_type_spectral().set_wavelengths_range().start = 450 + sensor1.set_type_spectral().set_wavelengths_range().end = 800 + sensor1.set_type_spectral().set_wavelengths_range().sampling = 15 sensor1.commit() assert ( sensor1.sensor_template_link.get().radiance_sensor_template.sensor_type_spectral.wavelengths_range.w_start @@ -835,9 +837,12 @@ def test_create_radiance_sensor(speos: Speos): assert sensor1.sensor_template_link.get().radiance_sensor_template.integration_angle == 4.5 # dimensions - sensor1.set_dimensions().set_x_start(value=-10).set_x_end(value=10).set_x_sampling( - value=60 - ).set_y_start(value=-20).set_y_end(value=20).set_y_sampling(value=120) + sensor1.set_dimensions().x_start = -10 + sensor1.set_dimensions().x_end = 10 + sensor1.set_dimensions().x_sampling = 60 + sensor1.set_dimensions().y_start = -20 + sensor1.set_dimensions().y_end = 20 + sensor1.set_dimensions().y_sampling = 120 sensor1.commit() assert sensor1.sensor_template_link.get().radiance_sensor_template.HasField("dimensions") assert sensor1.sensor_template_link.get().radiance_sensor_template.dimensions.x_start == -10.0 @@ -923,9 +928,8 @@ def test_create_radiance_sensor(speos: Speos): ) # layer_type_sequence - sensor1.set_layer_type_sequence().set_maximum_nb_of_sequence( - value=5 - ).set_define_sequence_per_faces() + sensor1.set_layer_type_sequence().maximum_nb_of_sequence = 5 + sensor1.set_layer_type_sequence().set_define_sequence_per_faces() sensor1.commit() assert radiance_properties.HasField("layer_type_sequence") assert radiance_properties.layer_type_sequence.maximum_nb_of_sequence == 5 @@ -1053,7 +1057,7 @@ def test_create_3d_irradiance_sensor(speos: Speos): colorimetric_info = sensor_3d.sensor_template_link.get().irradiance_3d.type_colorimetric assert colorimetric_info.wavelength_start == 400 assert colorimetric_info.wavelength_end == 700 - sensor_3d.set_type_colorimetric().set_wavelengths_range().set_start(500) + sensor_3d.set_type_colorimetric().set_wavelengths_range().start = 500 sensor_3d.commit() colorimetric_info = sensor_3d.sensor_template_link.get().irradiance_3d.type_colorimetric assert sensor_3d.get(key="wavelength_start") == 500 @@ -1159,7 +1163,7 @@ def test_reset_sensor(speos: Speos): 1, ] # server - sensor1.set_dimensions().set_x_start(0) + sensor1.set_dimensions().x_start = 0 sensor1.set_axis_system([1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1]) assert sensor1._sensor_template.irradiance_sensor_template.dimensions.x_start == 0 # local assert ( @@ -1256,14 +1260,14 @@ def test_irradiance_modify_after_reset(speos: Speos): sensor1._sensor_template.irradiance_sensor_template.sensor_type_spectral.wavelengths_range.w_start == 400 ) - sensor1.set_type_spectral().set_wavelengths_range().set_start(value=500) + sensor1.set_type_spectral().set_wavelengths_range().start = 500 assert ( sensor1._sensor_template.irradiance_sensor_template.sensor_type_spectral.wavelengths_range.w_start == 500 ) # Intermediate class for dimensions assert sensor1._sensor_template.irradiance_sensor_template.dimensions.x_start == -50 - sensor1.set_dimensions().set_x_start(-100) + sensor1.set_dimensions().x_start = -100 assert sensor1._sensor_template.irradiance_sensor_template.dimensions.x_start == -100 # Props @@ -1301,7 +1305,7 @@ def test_irradiance_modify_after_reset(speos: Speos): sensor1._sensor_instance.irradiance_properties.layer_type_sequence.maximum_nb_of_sequence == 10 ) - sensor1.set_layer_type_sequence().set_maximum_nb_of_sequence(value=15) + sensor1.set_layer_type_sequence().maximum_nb_of_sequence = 15 assert ( sensor1._sensor_instance.irradiance_properties.layer_type_sequence.maximum_nb_of_sequence == 15 @@ -1334,14 +1338,14 @@ def test_radiance_modify_after_reset(speos: Speos): sensor1._sensor_template.radiance_sensor_template.sensor_type_colorimetric.wavelengths_range.w_start == 400 ) - sensor1.set_type_colorimetric().set_wavelengths_range().set_start(value=500) + sensor1.set_type_colorimetric().set_wavelengths_range().start = 500 assert ( sensor1._sensor_template.radiance_sensor_template.sensor_type_colorimetric.wavelengths_range.w_start == 500 ) # Intermediate class for dimensions assert sensor1._sensor_template.radiance_sensor_template.dimensions.x_start == -50 - sensor1.set_dimensions().set_x_start(-100) + sensor1.set_dimensions().x_start = -100 assert sensor1._sensor_template.radiance_sensor_template.dimensions.x_start == -100 ## Props @@ -1379,7 +1383,7 @@ def test_radiance_modify_after_reset(speos: Speos): sensor1._sensor_instance.radiance_properties.layer_type_sequence.maximum_nb_of_sequence == 10 ) - sensor1.set_layer_type_sequence().set_maximum_nb_of_sequence(value=15) + sensor1.set_layer_type_sequence().maximum_nb_of_sequence = 15 assert ( sensor1._sensor_instance.radiance_properties.layer_type_sequence.maximum_nb_of_sequence == 15 @@ -1421,7 +1425,7 @@ def test_camera_modify_after_reset(speos: Speos): sensor1._sensor_template.camera_sensor_template.sensor_mode_photometric.wavelengths_range.w_start == 400 ) - sensor1.set_mode_photometric().set_wavelengths_range().set_start(value=500) + sensor1.set_mode_photometric().set_wavelengths_range().start = 500 assert ( sensor1._sensor_template.camera_sensor_template.sensor_mode_photometric.wavelengths_range.w_start == 500 From 1f7a9f41fe7f865899eafad71fa88649d1dda449 Mon Sep 17 00:00:00 2001 From: plu Date: Wed, 6 Aug 2025 13:22:51 +0100 Subject: [PATCH 19/52] fix sensor refactor methods related in prism-example.py --- examples/core/prism-example.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/core/prism-example.py b/examples/core/prism-example.py index 081b03420..f32124f2c 100644 --- a/examples/core/prism-example.py +++ b/examples/core/prism-example.py @@ -93,7 +93,9 @@ irr_features = p.find(name=".*", name_regex=True, feature_type=SensorIrradiance) irr = irr_features[0] -irr.set_type_spectral().set_wavelengths_range().set_start(500).set_end(600).set_sampling(11) +irr.set_type_spectral().set_wavelengths_range().start = 500 +irr.set_type_spectral().set_wavelengths_range().end = 600 +irr.set_type_spectral().set_wavelengths_range().sampling = 11 irr.commit() # Create and add a new sensor, e.g. 3d irradiance sensor From 8f42a9c9917416699dbcb50efc18958ed0d20dfe Mon Sep 17 00:00:00 2001 From: plu Date: Wed, 6 Aug 2025 13:34:50 +0100 Subject: [PATCH 20/52] fix issue in project.py --- examples/core/project.py | 2 +- src/ansys/speos/core/source.py | 43 ---------------------------------- 2 files changed, 1 insertion(+), 44 deletions(-) diff --git a/examples/core/project.py b/examples/core/project.py index 7a0a298a7..139233de3 100644 --- a/examples/core/project.py +++ b/examples/core/project.py @@ -193,7 +193,7 @@ # modify the surface source, e.g. surface source wavelength: -src.set_spectrum().set_monochromatic.wavelength = 550 +src.set_spectrum().set_monochromatic().wavelength = 550 src.commit() diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index 14266bd9b..77bfc600c 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -658,8 +658,6 @@ def set_flux_luminous(self) -> SourceLuminaire.Luminous: elif self._type._luminous_flux is not self._source_template.luminaire.luminous_flux: self._type._luminous_flux = self._source_template.luminaire.luminous_flux return self._type - # self._source_template.luminaire.luminous_flux.luminous_value = value - # return self def set_flux_radiant(self) -> SourceLuminaire.Radiant: """Set radiant flux. @@ -684,8 +682,6 @@ def set_flux_radiant(self) -> SourceLuminaire.Radiant: elif self._type._radiant_flux is not self._source_template.luminaire.radiant_flux: self._type._radiant_flux = self._source_template.luminaire.radiant_flux return self._type - # self._source_template.luminaire.radiant_flux.radiant_value = value - # return self @property def intensity_file_uri(self) -> str: @@ -885,22 +881,6 @@ def ray_file_uri(self, uri: Union[Path, str]) -> None: """ self._source_template.rayfile.ray_file_uri = str(uri) - # def set_ray_file_uri(self, uri: str) -> SourceRayFile: - # """Set ray file. - # - # Parameters - # ---------- - # uri : str - # Rayfile format file uri (.ray or .tm25ray files expected). - # - # Returns - # ------- - # ansys.speos.core.source.SourceRayFile - # RayFile source. - # """ - # self._source_template.rayfile.ray_file_uri = uri - # return self - def set_flux_from_ray_file(self) -> SourceRayFile: """Take flux from ray file provided. @@ -935,8 +915,6 @@ def set_flux_luminous(self) -> SourceRayFile.Luminous: elif self._type._luminous_flux is not self._source_template.rayfile.luminous_flux: self._type._luminous_flux = self._source_template.rayfile.luminous_flux return self._type - # self._source_template.rayfile.luminous_flux.luminous_value = value - # return self def set_flux_radiant(self) -> SourceRayFile.Radiant: """Set radiant flux. @@ -961,8 +939,6 @@ def set_flux_radiant(self) -> SourceRayFile.Radiant: elif self._type._radiant_flux is not self._source_template.rayfile.radiant_flux: self._type._radiant_flux = self._source_template.rayfile.radiant_flux return self._type - # self._source_template.rayfile.radiant_flux.radiant_value = value - # return self def set_spectrum_from_ray_file(self) -> SourceRayFile: """Take spectrum from ray file provided. @@ -1028,25 +1004,6 @@ def axis_system(self, axis_system: list[float]) -> None: """ self._source_instance.rayfile_properties.axis_system[:] = axis_system - # def set_axis_system(self, axis_system: Optional[List[float]] = None) -> SourceRayFile: - # """Set position of the source. - # - # Parameters - # ---------- - # axis_system : Optional[List[float]] - # Position of the source [Ox Oy Oz Xx Xy Xz Yx Yy Yz Zx Zy Zz]. - # By default, ``[0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]``. - # - # Returns - # ------- - # ansys.speos.core.source.SourceRayFile - # RayFile Source. - # """ - # if axis_system is None: - # axis_system = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1] - # self._source_instance.rayfile_properties.axis_system[:] = axis_system - # return self - def set_exit_geometries(self, exit_geometries: Optional[List[GeoRef]] = None) -> SourceRayFile: """Set exit geometries. From 1719bf584ac1ba698dd431813a920477071ac64f Mon Sep 17 00:00:00 2001 From: plu Date: Wed, 6 Aug 2025 14:02:02 +0100 Subject: [PATCH 21/52] fix example issue --- examples/core/simulation.py | 2 +- examples/core/source.py | 6 +++--- src/ansys/speos/core/source.py | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/core/simulation.py b/examples/core/simulation.py index e95950587..d24a1dd44 100644 --- a/examples/core/simulation.py +++ b/examples/core/simulation.py @@ -103,7 +103,7 @@ # ### Prepare a surface source source1 = p.create_source(name=SOURCE_NAME) -source1.set_exitance_constant(geometries=[(face_1, True)]) +source1.set_exitance_constant().geometries = [(face_1, True)] # define a spectrum which is not monochromatic so it can be used in both direct and inverse # simulation source1.set_spectrum().set_blackbody() diff --git a/examples/core/source.py b/examples/core/source.py index e42e6ed72..0634c6fc6 100644 --- a/examples/core/source.py +++ b/examples/core/source.py @@ -115,7 +115,7 @@ def create_face(body): intensity_file_path = str(assets_data_path / IES) source2 = p.create_source(name="Luminaire.2", feature_type=SourceLuminaire) source2.intensity_file_uri = intensity_file_path -source2.flux_radiant = 1.0 # select flux radiant +source2.set_flux_radiant().value = 1.0 # select flux radiant # choose the source location [Origin, Xvector, Yvector, Zvector] source2.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 @@ -140,7 +140,7 @@ def create_face(body): # > changes. # > If you don't, you will still only watch what is committed on the server. -source1.flux_radiant = 1.2 # modify radiant flux value +source1.set_flux_radiant().value = 1.2 # modify radiant flux value source1.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 @@ -150,7 +150,7 @@ def create_face(body): # # Possibility to reset local values from the one available in the server. -source1.flux_luminous = 683.0 # modify to luminous flux BUT no commit +source1.set_flux_luminous().value = 683.0 # 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 diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index 77bfc600c..02f4d6dda 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -44,6 +44,7 @@ import ansys.speos.core.generic.general_methods as general_methods from ansys.speos.core.generic.visualization_methods import _VisualArrow, _VisualData from ansys.speos.core.geo_ref import GeoRef +import ansys.speos.core.intensity as intensity from ansys.speos.core.intensity import Intensity from ansys.speos.core.kernel.client import SpeosClient from ansys.speos.core.kernel.scene import ProtoScene @@ -1481,7 +1482,7 @@ def set_flux_luminous_intensity(self) -> SourceSurface.Intensity: # self._source_template.surface.luminous_intensity_flux.luminous_intensity_value = value # return self - def set_intensity(self) -> Intensity: + def set_intensity(self) -> intensity.Intensity: """Set intensity. Returns From c7fc8af2f854ba48be916f6b46422aa257f9af22 Mon Sep 17 00:00:00 2001 From: plu Date: Wed, 6 Aug 2025 14:15:32 +0100 Subject: [PATCH 22/52] fix issue in document example --- examples/workflow/combine-speos.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/workflow/combine-speos.py b/examples/workflow/combine-speos.py index ad47b70a5..4d7f2f163 100644 --- a/examples/workflow/combine-speos.py +++ b/examples/workflow/combine-speos.py @@ -135,10 +135,9 @@ # + src = p.create_source(name="Luminaire.1", feature_type=SourceLuminaire) -src.set_intensity_file_uri( - uri=str(assets_data_path / "IES_C_DETECTOR.ies") -).set_spectrum().set_daylightfluorescent() -src.set_axis_system([0, 10000, 50000, 1, 0, 0, 0, 1, 0, 0, 0, 1]) +src.intensity_file_uri = assets_data_path / "IES_C_DETECTOR.ies" +src.set_spectrum().set_daylightfluorescent() +src.axis_system = [0, 10000, 50000, 1, 0, 0, 0, 1, 0, 0, 0, 1] src.commit() # - From 4ebbc84fdb8f74f285289198d2453af76a7dc670 Mon Sep 17 00:00:00 2001 From: plu Date: Wed, 6 Aug 2025 14:45:54 +0100 Subject: [PATCH 23/52] improve code coverage --- tests/core/test_sensor.py | 11 +++++++++++ tests/core/test_source.py | 12 ++++++++++++ tests/core/test_spectrum.py | 2 ++ 3 files changed, 25 insertions(+) diff --git a/tests/core/test_sensor.py b/tests/core/test_sensor.py index b466663a6..71199379b 100644 --- a/tests/core/test_sensor.py +++ b/tests/core/test_sensor.py @@ -489,6 +489,9 @@ def test_create_irradiance_sensor(speos: Speos): sensor1.set_type_colorimetric().set_wavelengths_range().end = 800 sensor1.set_type_colorimetric().set_wavelengths_range().sampling = 15 sensor1.commit() + assert sensor1.set_type_colorimetric().set_wavelengths_range().start == 450 + assert sensor1.set_type_colorimetric().set_wavelengths_range().end == 800 + assert sensor1.set_type_colorimetric().set_wavelengths_range().sampling == 15 sensor_template = sensor1.sensor_template_link.get().irradiance_sensor_template assert sensor_template.sensor_type_colorimetric.wavelengths_range.w_start == 450 assert sensor_template.sensor_type_colorimetric.wavelengths_range.w_end == 800 @@ -691,6 +694,7 @@ def test_create_irradiance_sensor(speos: Speos): # layer_type_incidence_angle sensor1.set_layer_type_incidence_angle().sampling = 8 sensor1.commit() + assert sensor1.set_layer_type_incidence_angle().sampling == 8 assert irra_properties.HasField("layer_type_incidence_angle") assert irra_properties.layer_type_incidence_angle.sampling == 8 @@ -844,6 +848,12 @@ def test_create_radiance_sensor(speos: Speos): sensor1.set_dimensions().y_end = 20 sensor1.set_dimensions().y_sampling = 120 sensor1.commit() + assert sensor1.set_dimensions().x_start == -10 + assert sensor1.set_dimensions().x_end == 10 + assert sensor1.set_dimensions().x_sampling == 60 + assert sensor1.set_dimensions().y_start == -20 + assert sensor1.set_dimensions().y_end == 20 + assert sensor1.set_dimensions().y_sampling == 120 assert sensor1.sensor_template_link.get().radiance_sensor_template.HasField("dimensions") assert sensor1.sensor_template_link.get().radiance_sensor_template.dimensions.x_start == -10.0 assert sensor1.sensor_template_link.get().radiance_sensor_template.dimensions.x_end == 10.0 @@ -931,6 +941,7 @@ def test_create_radiance_sensor(speos: Speos): sensor1.set_layer_type_sequence().maximum_nb_of_sequence = 5 sensor1.set_layer_type_sequence().set_define_sequence_per_faces() sensor1.commit() + assert sensor1.set_layer_type_sequence().maximum_nb_of_sequence == 5 assert radiance_properties.HasField("layer_type_sequence") assert radiance_properties.layer_type_sequence.maximum_nb_of_sequence == 5 assert ( diff --git a/tests/core/test_source.py b/tests/core/test_source.py index ab069421a..b97a383d2 100644 --- a/tests/core/test_source.py +++ b/tests/core/test_source.py @@ -67,6 +67,7 @@ def test_create_luminaire_source(speos: Speos): # intensity_file_uri source1.intensity_file_uri = Path(test_path) / "IES_C_DETECTOR.ies" source1.commit() + assert source1.intensity_file_uri == str(Path(test_path) / "IES_C_DETECTOR.ies") assert source1.source_template_link is not None assert source1.source_template_link.get().luminaire.intensity_file_uri != "" @@ -199,6 +200,7 @@ def test_create_surface_source(speos: Speos): # luminous_intensity_flux source1.set_flux_luminous_intensity().value = 5.5 source1.commit() + assert source1.set_flux_luminous_intensity().value == 5.5 assert source1.source_template_link.get().surface.HasField("luminous_intensity_flux") assert ( source1.source_template_link.get().surface.luminous_intensity_flux.luminous_intensity_value @@ -211,6 +213,9 @@ def test_create_surface_source(speos: Speos): ) source1.set_spectrum_from_xmp_file() source1.commit() + assert source1.set_exitance_variable().xmp_file_uri == str( + Path(test_path) / "PROJECT.Direct-no-Ray.Irradiance Ray Spectral.xmp" + ) assert source1.source_template_link.get().surface.HasField("exitance_variable") assert source1.source_template_link.get().surface.exitance_variable.exitance_xmp_file_uri != "" assert source1.source_template_link.get().surface.HasField("spectrum_from_xmp_file") @@ -231,6 +236,7 @@ def test_create_surface_source(speos: Speos): # exitance_variable axis_plane source1.set_exitance_variable().axis_plane = [10, 10, 15, 1, 0, 0, 0, 1, 0] source1.commit() + assert source1.set_exitance_variable().axis_plane == [10, 10, 15, 1, 0, 0, 0, 1, 0] assert surface_properties.HasField("exitance_variable_properties") assert surface_properties.exitance_variable_properties.axis_plane == [ 10, @@ -251,6 +257,10 @@ def test_create_surface_source(speos: Speos): ] source1.set_spectrum().set_blackbody() source1.commit() + assert source1.set_exitance_constant().geometries == [ + (GeoRef.from_native_link("BodyB/FaceB1"), False), + (GeoRef.from_native_link("BodyB/FaceB2"), True), + ] assert surface_properties.HasField("exitance_constant_properties") assert len(surface_properties.exitance_constant_properties.geo_paths) == 2 assert surface_properties.exitance_constant_properties.geo_paths[0].geo_path == "BodyB/FaceB1" @@ -297,6 +307,7 @@ def test_create_rayfile_source(speos: Speos): # ray_file_uri source1.ray_file_uri = Path(test_path) / "Rays.ray" source1.commit() + assert source1.ray_file_uri == str(Path(test_path) / "Rays.ray") assert source1.source_template_link is not None assert source1.source_template_link.get().HasField("rayfile") assert source1.source_template_link.get().rayfile.ray_file_uri != "" @@ -336,6 +347,7 @@ def test_create_rayfile_source(speos: Speos): # axis_system source1.axis_system = [50, 40, 50, 1, 0, 0, 0, 1, 0, 0, 0, 1] source1.commit() + assert source1.axis_system == [50, 40, 50, 1, 0, 0, 0, 1, 0, 0, 0, 1] assert source1._source_instance.HasField("rayfile_properties") assert source1._source_instance.rayfile_properties.axis_system == [ 50, diff --git a/tests/core/test_spectrum.py b/tests/core/test_spectrum.py index 994e87b93..41c75579c 100644 --- a/tests/core/test_spectrum.py +++ b/tests/core/test_spectrum.py @@ -52,6 +52,8 @@ def test_create_spectrum(speos: Speos): spectrum1.set_sampled().wavelengths = [300, 400, 500] spectrum1.set_sampled().values = [30, 20, 70] spectrum1.commit() + assert spectrum1.set_sampled().wavelengths == [300, 400, 500] + assert spectrum1.set_sampled().values == [30, 20, 70] assert spectrum1.spectrum_link.get().HasField("sampled") assert spectrum1.spectrum_link.get().sampled.wavelengths == [300, 400, 500] assert spectrum1.spectrum_link.get().sampled.values == [30, 20, 70] From 94b53f3549d7c4df9b3dd6e3209b9f6cab836b89 Mon Sep 17 00:00:00 2001 From: plu Date: Wed, 6 Aug 2025 14:54:48 +0100 Subject: [PATCH 24/52] issue fix in test --- tests/core/test_source.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/core/test_source.py b/tests/core/test_source.py index b97a383d2..880e7664d 100644 --- a/tests/core/test_source.py +++ b/tests/core/test_source.py @@ -257,10 +257,7 @@ def test_create_surface_source(speos: Speos): ] source1.set_spectrum().set_blackbody() source1.commit() - assert source1.set_exitance_constant().geometries == [ - (GeoRef.from_native_link("BodyB/FaceB1"), False), - (GeoRef.from_native_link("BodyB/FaceB2"), True), - ] + assert len(source1.set_exitance_constant().geometries) == 2 assert surface_properties.HasField("exitance_constant_properties") assert len(surface_properties.exitance_constant_properties.geo_paths) == 2 assert surface_properties.exitance_constant_properties.geo_paths[0].geo_path == "BodyB/FaceB1" From 56dd33d1c5ff56f97e549beb215cc5fadca4bea4 Mon Sep 17 00:00:00 2001 From: plu Date: Wed, 6 Aug 2025 15:16:35 +0100 Subject: [PATCH 25/52] improve code coverage --- src/ansys/speos/core/spectrum.py | 11 +++-------- tests/core/test_spectrum.py | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/ansys/speos/core/spectrum.py b/src/ansys/speos/core/spectrum.py index 61383a57e..9172eb5bc 100644 --- a/src/ansys/speos/core/spectrum.py +++ b/src/ansys/speos/core/spectrum.py @@ -88,7 +88,7 @@ def __init__( stable_ctr: bool = False, ): if not stable_ctr: - msg = "WavelengthsRange class instantiated outside of class scope" + msg = "Monochromatic class instantiated outside of class scope" raise RuntimeError(msg) self._monochromatic = monochromatic @@ -149,7 +149,7 @@ def __init__( stable_ctr: bool = False, ): if not stable_ctr: - msg = "WavelengthRange class instantiated outside of class scope" + msg = "Blackbody class instantiated outside of class scope" raise RuntimeError(msg) self._blackbody = blackbody @@ -211,7 +211,7 @@ def __init__( stable_ctr: bool = False, ): if not stable_ctr: - msg = "WavelengthRange class instantiated outside of class scope" + msg = "Sampled class instantiated outside of class scope" raise RuntimeError(msg) self._sampled = sampled # if default_values: @@ -323,8 +323,6 @@ def set_monochromatic(self) -> Spectrum.Monochromatic: elif self._type._monochromatic is not self._spectrum.monochromatic: self._type._monochromatic = self._spectrum.monochromatic return self._type - # self._spectrum.monochromatic.wavelength = wavelength - # return self def set_blackbody(self) -> Spectrum.Blackbody: """Set the spectrum as blackbody. @@ -375,9 +373,6 @@ def set_sampled(self) -> Spectrum.Sampled: elif self._type._sampled is not self._spectrum.sampled: self._type._sampled = self._spectrum.sampled return self._type - # self._spectrum.sampled.wavelengths[:] = wavelengths - # self._spectrum.sampled.values[:] = values - # return self def set_library(self, file_uri: str) -> Spectrum: """Set the spectrum as library. diff --git a/tests/core/test_spectrum.py b/tests/core/test_spectrum.py index 41c75579c..68c2d32c7 100644 --- a/tests/core/test_spectrum.py +++ b/tests/core/test_spectrum.py @@ -24,6 +24,8 @@ from pathlib import Path +import pytest + from ansys.speos.core import Spectrum, Speos from tests.conftest import test_path @@ -39,12 +41,14 @@ def test_create_spectrum(speos: Speos): # monochromatic spectrum1.set_monochromatic().wavelength = 777 spectrum1.commit() + assert spectrum1.set_monochromatic().wavelength == 777 assert spectrum1.spectrum_link.get().HasField("monochromatic") assert spectrum1.spectrum_link.get().monochromatic.wavelength == 777 # blackbody spectrum1.set_blackbody().temperature = 3000 spectrum1.commit() + assert spectrum1.set_blackbody().temperature == 3000 assert spectrum1.spectrum_link.get().HasField("blackbody") assert spectrum1.spectrum_link.get().blackbody.temperature == 3000 @@ -100,6 +104,28 @@ def test_create_spectrum(speos: Speos): assert spectrum1.spectrum_link.get().HasField("predefined") assert spectrum1.spectrum_link.get().predefined.HasField("highpressuresodium") + with pytest.raises(RuntimeError, match="Blackbody class instantiated outside of class scopee"): + Spectrum.Blackbody( + blackbody=spectrum1._spectrum.blackbody, + default_values=True, + stable_ctr=False, + ) + + with pytest.raises( + RuntimeError, match="Monochromatic class instantiated outside of class scopee" + ): + Spectrum.Monochromatic( + monochromatic=spectrum1._spectrum.monochromatic, + default_values=True, + stable_ctr=False, + ) + + with pytest.raises(RuntimeError, match="Sampled class instantiated outside of class scopee"): + Spectrum.Sampled( + sampled=spectrum1._spectrum.sampled, + default_values=True, + stable_ctr=False, + ) spectrum1.delete() From 749ea89bb32fdfbd159d19bebfc9402c8905093e Mon Sep 17 00:00:00 2001 From: plu Date: Wed, 6 Aug 2025 15:58:37 +0100 Subject: [PATCH 26/52] improve code coverage --- tests/core/test_source.py | 43 +++++++++++++++++++++++++++++++++++++ tests/core/test_spectrum.py | 6 +++--- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/tests/core/test_source.py b/tests/core/test_source.py index 880e7664d..1b50b67e3 100644 --- a/tests/core/test_source.py +++ b/tests/core/test_source.py @@ -25,6 +25,8 @@ import datetime from pathlib import Path +import pytest + from ansys.speos.core import GeoRef, Project, Speos from ansys.speos.core.source import ( SourceAmbientNaturalLight, @@ -134,6 +136,20 @@ def test_create_luminaire_source(speos: Speos): 1, ] + with pytest.raises(RuntimeError, match="Luminous class instantiated outside of class scope"): + SourceLuminaire.Luminous( + luminous_flux=source1._source_template.luminaire.luminous_flux, + default_values=True, + stable_ctr=False, + ) + + with pytest.raises(RuntimeError, match="Radiant class instantiated outside of class scope"): + SourceLuminaire.Radiant( + radiant_flux=source1._source_template.luminaire.radiant_flux, + default_values=True, + stable_ctr=False, + ) + source1.delete() assert len(p.scene_link.get().sources) == 0 @@ -269,6 +285,33 @@ def test_create_surface_source(speos: Speos): assert surface_properties.HasField("exitance_constant_properties") assert len(surface_properties.exitance_constant_properties.geo_paths) == 0 + with pytest.raises(RuntimeError, match="Intensity class instantiated outside of class scope"): + SourceSurface.Intensity( + intensity_flux=source1._source_template.surface.luminous_intensity_flux, + default_values=True, + stable_ctr=False, + ) + + with pytest.raises( + RuntimeError, match="ExitanceConstant class instantiated outside of class scope" + ): + SourceSurface.ExitanceConstant( + exitance_constant=source1._source_template.surface.exitance_constant, + exitance_constant_props=source1._source_instance.surface_properties.exitance_constant_properties, + default_values=True, + stable_ctr=False, + ) + + with pytest.raises( + RuntimeError, match="ExitanceVariable class instantiated outside of class scope" + ): + SourceSurface.ExitanceVariable( + exitance_variable=source1._source_template.surface.exitance_variable, + exitance_variable_props=source1._source_instance.surface_properties.exitance_variable_properties, + default_values=True, + stable_ctr=False, + ) + source1.delete() diff --git a/tests/core/test_spectrum.py b/tests/core/test_spectrum.py index 68c2d32c7..05ebafdd9 100644 --- a/tests/core/test_spectrum.py +++ b/tests/core/test_spectrum.py @@ -104,7 +104,7 @@ def test_create_spectrum(speos: Speos): assert spectrum1.spectrum_link.get().HasField("predefined") assert spectrum1.spectrum_link.get().predefined.HasField("highpressuresodium") - with pytest.raises(RuntimeError, match="Blackbody class instantiated outside of class scopee"): + with pytest.raises(RuntimeError, match="Blackbody class instantiated outside of class scope"): Spectrum.Blackbody( blackbody=spectrum1._spectrum.blackbody, default_values=True, @@ -112,7 +112,7 @@ def test_create_spectrum(speos: Speos): ) with pytest.raises( - RuntimeError, match="Monochromatic class instantiated outside of class scopee" + RuntimeError, match="Monochromatic class instantiated outside of class scope" ): Spectrum.Monochromatic( monochromatic=spectrum1._spectrum.monochromatic, @@ -120,7 +120,7 @@ def test_create_spectrum(speos: Speos): stable_ctr=False, ) - with pytest.raises(RuntimeError, match="Sampled class instantiated outside of class scopee"): + with pytest.raises(RuntimeError, match="Sampled class instantiated outside of class scope"): Spectrum.Sampled( sampled=spectrum1._spectrum.sampled, default_values=True, From aaa84d0a3c4966a390f5b4173117db803840c85e Mon Sep 17 00:00:00 2001 From: Pengyuan LU <89462462+pluAtAnsys@users.noreply.github.com> Date: Thu, 7 Aug 2025 10:22:12 +0100 Subject: [PATCH 27/52] Update src/ansys/speos/core/source.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Stefan Thöne <86405327+StefanThoene@users.noreply.github.com> --- src/ansys/speos/core/source.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index 02f4d6dda..7d4d2f1da 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -733,7 +733,7 @@ def axis_system(self) -> list[float]: Position of the source [Ox Oy Oz Xx Xy Xz Yx Yy Yz Zx Zy Zz]. By default, ``[0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]``. """ - return self._source_instance.luminaire_properties.axis_system[:] + return self._source_instance.luminaire_properties.axis_system @axis_system.setter def axis_system(self, axis_system: list[float]) -> None: From 5426819ca538195d7185ebecbf6759f2b18d4694 Mon Sep 17 00:00:00 2001 From: Pengyuan LU <89462462+pluAtAnsys@users.noreply.github.com> Date: Thu, 7 Aug 2025 10:22:56 +0100 Subject: [PATCH 28/52] Update src/ansys/speos/core/source.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Stefan Thöne <86405327+StefanThoene@users.noreply.github.com> --- src/ansys/speos/core/source.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index 7d4d2f1da..b775efd0d 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -585,7 +585,7 @@ def __init__( if default_values: # Default values self.set_flux_from_intensity_file().set_spectrum().set_incandescent() - self.axis_system = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1] + self.axis_system = ORIGIN @property def visual_data(self) -> _VisualData: From 28ca1dc61dd0a6abc7aa6f4849e2f02d0667f8a8 Mon Sep 17 00:00:00 2001 From: Pengyuan LU <89462462+pluAtAnsys@users.noreply.github.com> Date: Thu, 7 Aug 2025 10:23:06 +0100 Subject: [PATCH 29/52] Update src/ansys/speos/core/source.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Stefan Thöne <86405327+StefanThoene@users.noreply.github.com> --- src/ansys/speos/core/source.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index b775efd0d..42f7ed025 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -40,7 +40,7 @@ ) import ansys.speos.core.body as body import ansys.speos.core.face as face -from ansys.speos.core.generic.constants import SOURCE +from ansys.speos.core.generic.constants import SOURCE, ORIGIN import ansys.speos.core.generic.general_methods as general_methods from ansys.speos.core.generic.visualization_methods import _VisualArrow, _VisualData from ansys.speos.core.geo_ref import GeoRef From 5767315d6ca2488031e8ae95a8165e7bcec6bd12 Mon Sep 17 00:00:00 2001 From: Pengyuan LU <89462462+pluAtAnsys@users.noreply.github.com> Date: Thu, 7 Aug 2025 10:23:13 +0100 Subject: [PATCH 30/52] Update src/ansys/speos/core/generic/constants.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Stefan Thöne <86405327+StefanThoene@users.noreply.github.com> --- src/ansys/speos/core/generic/constants.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ansys/speos/core/generic/constants.py b/src/ansys/speos/core/generic/constants.py index 19cea4017..42b2464d5 100644 --- a/src/ansys/speos/core/generic/constants.py +++ b/src/ansys/speos/core/generic/constants.py @@ -38,7 +38,8 @@ """Maximum message Size accepted by grpc channel, By default, 4194304. """ - +ORIGIN = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1] +"""Global Origin""" class SPECTRUM: """Constant class for Spectrum.""" From 06c33edb6cd726d5f5c55de58f483ef12da308e4 Mon Sep 17 00:00:00 2001 From: Pengyuan LU <89462462+pluAtAnsys@users.noreply.github.com> Date: Thu, 7 Aug 2025 10:23:21 +0100 Subject: [PATCH 31/52] Update src/ansys/speos/core/source.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Stefan Thöne <86405327+StefanThoene@users.noreply.github.com> --- src/ansys/speos/core/source.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index 42f7ed025..3a3742a0c 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -814,7 +814,7 @@ def __init__( if default_values: # Default values self.set_flux_from_ray_file().set_spectrum_from_ray_file() - self.axis_system = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1] + self.axis_system = ORIGIN @property def visual_data(self) -> _VisualData: From 4e520bc85a1a7c53b475d78bf5db348d1b6e7ddc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 7 Aug 2025 09:23:23 +0000 Subject: [PATCH 32/52] ci: auto fixes from pre-commit.com hooks. for more information, see https://pre-commit.ci --- src/ansys/speos/core/generic/constants.py | 1 + src/ansys/speos/core/source.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ansys/speos/core/generic/constants.py b/src/ansys/speos/core/generic/constants.py index 42b2464d5..36ba8da67 100644 --- a/src/ansys/speos/core/generic/constants.py +++ b/src/ansys/speos/core/generic/constants.py @@ -41,6 +41,7 @@ ORIGIN = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1] """Global Origin""" + class SPECTRUM: """Constant class for Spectrum.""" diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index 3a3742a0c..6e3c4952c 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -40,7 +40,7 @@ ) import ansys.speos.core.body as body import ansys.speos.core.face as face -from ansys.speos.core.generic.constants import SOURCE, ORIGIN +from ansys.speos.core.generic.constants import ORIGIN, SOURCE import ansys.speos.core.generic.general_methods as general_methods from ansys.speos.core.generic.visualization_methods import _VisualArrow, _VisualData from ansys.speos.core.geo_ref import GeoRef From 10c6a2dd7eef5279429705e42edb46f2d9e588bf Mon Sep 17 00:00:00 2001 From: Pengyuan LU <89462462+pluAtAnsys@users.noreply.github.com> Date: Thu, 7 Aug 2025 10:24:11 +0100 Subject: [PATCH 33/52] Update src/ansys/speos/core/source.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Stefan Thöne <86405327+StefanThoene@users.noreply.github.com> --- src/ansys/speos/core/source.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index 6e3c4952c..eadf9e7ec 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -1232,7 +1232,7 @@ def __init__( if default_values: # Default values self._exitance_variable.SetInParent() - self.axis_plane = [0, 0, 0, 1, 0, 0, 0, 1, 0] + self.axis_plane = ORIGIN[0:8] @property def xmp_file_uri(self) -> str: From 3d20f799dde7f18ebdcf47d18e590fc383e3d3cd Mon Sep 17 00:00:00 2001 From: plu Date: Thu, 7 Aug 2025 12:02:33 +0100 Subject: [PATCH 34/52] fix issue and add exitgeometry sub-class --- src/ansys/speos/core/source.py | 111 +++++++++++++++++++++++++++------ tests/core/test_simulation.py | 17 ++--- tests/core/test_source.py | 20 +++--- 3 files changed, 113 insertions(+), 35 deletions(-) diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index eadf9e7ec..82a10ef76 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -773,6 +773,74 @@ class SourceRayFile(BaseSource): Uses default values when True. """ + class ExitGeometries: + """ExitGeometries of rayfile source. + + By default, ExitGeometries list is set to be empty. + + Parameters + ---------- + rayfile_props : ansys.api.speos.scene.v2.scene_pb2.RayFileProperties + protobuf object to modify. + default_values : bool + Uses default values when True. + stable_ctr : bool + Variable to indicate if usage is inside class scope + + Notes + ----- + **Do not instantiate this class yourself**, use set_exit_geometries + method available in Source classes. + """ + + def __init__( + self, + rayfile_props: scene_pb2.RayFileProperties, + default_values: bool = True, + stable_ctr: bool = False, + ): + if not stable_ctr: + msg = "ExitGeometries class instantiated outside of class scope" + raise RuntimeError(msg) + self._rayfile_props = rayfile_props + if default_values: + self.geometries = [] + + @property + def geometries(self) -> List[GeoRef]: + """Get list of exit geometries. + + Returns + ------- + List[GeoRef] + Exit Geometries that will use this rayfile source. + By default, ``[]``. + + """ + return self._rayfile_props.exit_geometries.geo_paths + + @geometries.setter + def geometries(self, exit_geometries: Optional[List[GeoRef]]) -> None: + """Set exit geometries. + + Parameters + ---------- + exit_geometries: List[ansys.speos.core.geo_ref.GeoRef] + Exit Geometries that will use this rayfile source. + By default, ``[]``. + + Returns + ------- + None + + """ + if not exit_geometries or len(exit_geometries) == 0: + self._rayfile_props.ClearField("exit_geometries") + else: + self._rayfile_props.exit_geometries.geo_paths[:] = [ + gr.to_native_link() for gr in exit_geometries + ] + @general_methods.min_speos_version(25, 2, 0) def __init__( self, @@ -810,6 +878,8 @@ def __init__( self._name = name # Attribute gathering more complex flux type self._type = None + # Attribute gathering more complex exit geometries settings + self._exit_geometry_type = None if default_values: # Default values @@ -1005,28 +1075,33 @@ def axis_system(self, axis_system: list[float]) -> None: """ self._source_instance.rayfile_properties.axis_system[:] = axis_system - def set_exit_geometries(self, exit_geometries: Optional[List[GeoRef]] = None) -> SourceRayFile: + def set_exit_geometries(self) -> SourceRayFile.ExitGeometries: """Set exit geometries. - Parameters - ---------- - exit_geometries : List[ansys.speos.core.geo_ref.GeoRef] - Exit Geometries that will use this rayfile source. - By default, ``[]``. - Returns ------- - ansys.speos.core.source.SourceRayFile - RayFile Source. + ansys.speos.core.source.SourceRayFile.ExitGeometries + ExitGeometries settings of rayfile source. """ - if not exit_geometries: - self._source_instance.rayfile_properties.ClearField("exit_geometries") - else: - self._source_instance.rayfile_properties.exit_geometries.geo_paths[:] = [ - gr.to_native_link() for gr in exit_geometries - ] - - return self + if self._exit_geometry_type is None and self._source_instance.rayfile_properties.HasField( + "exit_geometries" + ): + self._exit_geometry_type = SourceRayFile.ExitGeometries( + rayfile_props=self._source_instance.rayfile_properties, + default_values=False, + stable_ctr=True, + ) + elif not isinstance(self._exit_geometry_type, SourceRayFile.ExitGeometries): + self._exit_geometry_type = SourceRayFile.ExitGeometries( + rayfile_props=self._source_instance.rayfile_properties, + default_values=True, + stable_ctr=True, + ) + elif ( + self._exit_geometry_type._rayfile_props is not self._source_instance.rayfile_properties + ): + self._exit_geometry_type._rayfile_props = self._source_instance.rayfile_properties + return self._exit_geometry_type class SourceSurface(BaseSource): @@ -1232,7 +1307,7 @@ def __init__( if default_values: # Default values self._exitance_variable.SetInParent() - self.axis_plane = ORIGIN[0:8] + self.axis_plane = ORIGIN[0:9] @property def xmp_file_uri(self) -> str: diff --git a/tests/core/test_simulation.py b/tests/core/test_simulation.py index d3835841e..f99f27d42 100644 --- a/tests/core/test_simulation.py +++ b/tests/core/test_simulation.py @@ -1032,8 +1032,10 @@ def test_export_vtp(speos: Speos): ) sim = p5.find(name=".*", name_regex=True, feature_type=SimulationDirect)[0] sensor_irra = p5.find(name=".*", name_regex=True, feature_type=SensorIrradiance)[0] - sensor_irra.set_dimensions().x_sampling = 10 - sensor_irra.set_dimensions().x_sampling = 10 + resolution_x = 10 + resolution_y = 10 + sensor_irra.set_dimensions().x_sampling = resolution_x + sensor_irra.set_dimensions().y_sampling = resolution_y sensor_irra.set_type_photometric() sensor_irra.commit() speos_results, vtp_results = sim.compute_CPU(export_vtp=True) @@ -1048,8 +1050,6 @@ def test_export_vtp(speos: Speos): content = file.readlines() file.close() skip_lines = 9 if "SeparatedByLayer" in content[7] else 8 - resolution_x = 10 - resolution_y = 10 xmp_data = [] if "2" not in content[0]: # not spectral data for line in content[skip_lines : skip_lines + resolution_y]: @@ -1086,7 +1086,8 @@ def test_export_vtp(speos: Speos): ) sim = p6.find(name=".*", name_regex=True, feature_type=SimulationDirect)[0] sensor_irra = p6.find(name=".*", name_regex=True, feature_type=SensorIrradiance)[0] - sensor_irra.set_dimensions().set_x_sampling(10).set_y_sampling(10) + sensor_irra.set_dimensions().x_sampling = 10 + sensor_irra.set_dimensions().y_sampling = 10 sensor_irra.set_type_radiometric() sensor_irra.commit() speos_results, vtp_results = sim.compute_CPU(export_vtp=True) @@ -1103,7 +1104,8 @@ def test_export_vtp(speos: Speos): ) sim = p7.find(name=".*", name_regex=True, feature_type=SimulationDirect)[0] sensor_irra = p7.find(name=".*", name_regex=True, feature_type=SensorIrradiance)[0] - sensor_irra.set_dimensions().set_x_sampling(10).set_y_sampling(10) + sensor_irra.set_dimensions().x_sampling = 10 + sensor_irra.set_dimensions().y_sampling = 10 sensor_irra.set_type_colorimetric() sensor_irra.commit() @@ -1125,7 +1127,8 @@ def test_export_vtp(speos: Speos): ) sim = p8.find(name=".*", name_regex=True, feature_type=SimulationDirect)[0] sensor_irra = p8.find(name=".*", name_regex=True, feature_type=SensorIrradiance)[0] - sensor_irra.set_dimensions().set_x_sampling(10).set_y_sampling(10) + sensor_irra.set_dimensions().x_sampling = 10 + sensor_irra.set_dimensions().y_sampling = 10 sensor_irra.set_type_spectral() sensor_irra.commit() speos_results, vtp_results = sim.compute_CPU(export_vtp=True) diff --git a/tests/core/test_source.py b/tests/core/test_source.py index 1b50b67e3..c55c55bb3 100644 --- a/tests/core/test_source.py +++ b/tests/core/test_source.py @@ -405,13 +405,12 @@ def test_create_rayfile_source(speos: Speos): ] # exit_geometries - source1.set_exit_geometries( - exit_geometries=[ - GeoRef.from_native_link("BodyB"), - GeoRef.from_native_link("BodyC"), - ] - ) + source1.set_exit_geometries().geometries = [ + GeoRef.from_native_link("BodyB"), + GeoRef.from_native_link("BodyC"), + ] source1.commit() + assert len(source1.set_exit_geometries().geometries) == 2 assert source1._source_instance.rayfile_properties.HasField("exit_geometries") assert len(source1._source_instance.rayfile_properties.exit_geometries.geo_paths) == 2 assert source1._source_instance.rayfile_properties.exit_geometries.geo_paths == [ @@ -419,7 +418,7 @@ def test_create_rayfile_source(speos: Speos): "BodyC", ] - source1.set_exit_geometries() # use default [] to reset exit geometries + source1.set_exit_geometries().geometries = [] # use default [] to reset exit geometries source1.commit() assert source1._source_instance.rayfile_properties.HasField("exit_geometries") is False @@ -685,9 +684,10 @@ def test_reset_source(speos: Speos): # Change local data (on template and on instance) source1.set_flux_radiant().value = 3.5 # template - source1.set_exit_geometries( - exit_geometries=[GeoRef.from_native_link("TheBodyB/TheFaceB1")] - ) # instance + source1.set_exit_geometries().geometries = [ + GeoRef.from_native_link("TheBodyB/TheFaceB1") + ] # instance + assert len(source1.set_exit_geometries().geometries) == 1 assert source1.source_template_link.get().rayfile.HasField("flux_from_ray_file") assert source1._source_template.rayfile.HasField("radiant_flux") # local template assert p.scene_link.get().sources[0].rayfile_properties.exit_geometries.geo_paths == [] From 13130d055370f38442c7e72d27e53de53f854544 Mon Sep 17 00:00:00 2001 From: plu Date: Thu, 7 Aug 2025 12:08:07 +0100 Subject: [PATCH 35/52] improve code coverage --- tests/core/test_source.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/core/test_source.py b/tests/core/test_source.py index c55c55bb3..096a439ca 100644 --- a/tests/core/test_source.py +++ b/tests/core/test_source.py @@ -422,6 +422,15 @@ def test_create_rayfile_source(speos: Speos): source1.commit() assert source1._source_instance.rayfile_properties.HasField("exit_geometries") is False + with pytest.raises( + RuntimeError, match="ExitGeometries class instantiated outside of class scope" + ): + SourceRayFile.ExitGeometries( + rayfile_props=source1._source_instance.rayfile_properties, + default_values=True, + stable_ctr=False, + ) + source1.delete() From c14208f89a891ec26478d636b0d7b9379aa4e2a9 Mon Sep 17 00:00:00 2001 From: plu Date: Sun, 31 Aug 2025 11:07:46 +0100 Subject: [PATCH 36/52] refactor cheat_sheet_script.qmd content accordingly --- doc/source/cheat_sheet/cheat_sheet_script.qmd | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/doc/source/cheat_sheet/cheat_sheet_script.qmd b/doc/source/cheat_sheet/cheat_sheet_script.qmd index aec202615..3a918158b 100644 --- a/doc/source/cheat_sheet/cheat_sheet_script.qmd +++ b/doc/source/cheat_sheet/cheat_sheet_script.qmd @@ -127,12 +127,13 @@ s_source = project.create_source(name='Surface.1', feature_type=SourceSurface) # Choose one way to set source power # for any conflicting property the last set property counts s_source.set_flux_from_intensity_file() -s_source.set_flux_luminous(683) -s_source.set_flux_radiant(1) -s_source.set_flux_luminous_intensity(5) -s_source.set_exitance_constant( - [(core.GeoRef.from_native_link( - 'TheBodyB/TheFaceF'), False)]) +s_source.set_flux_luminous().value = 683 +s_source.set_flux_radiant().value = 1 +s_source.set_flux_luminous_intensity().value = 5 +s_source.set_exitance_constant().geometries = [ + (core.GeoRef.from_native_link( + 'TheBodyB/TheFaceF'), False) + ] s_int = s_source.set_intensity() s_int.set_cos(1,120) s_source.set_spectrum() @@ -150,13 +151,13 @@ r_source.set_ray_file_uri('path/ray.ray') # Choose one way to set source power # for any conflicting property the last set property counts r_source.set_flux_from_ray_file() -r_source.set_flux_luminous(683) -r_source.set_flux_radiant(1) +r_source.set_flux_luminous().value = 683 +r_source.set_flux_radiant().value = 1 r_source.set_spectrum_from_ray_file() -r_source.set_exit_geometries( - [core.GeoRef.from_native_link( - 'TheBodyB/TheFaceF')]) -r_source.set_axis_system([0,0,0,1,0,0,0,1,0,0,0,1]) +r_source.set_exit_geometries().geometries = [ + core.GeoRef.from_native_link('TheBodyB/TheFaceF'), + ] +r_source.axis_system = [0,0,0,1,0,0,0,1,0,0,0,1] r_source.commit() ``` From 7259117c90253b006a7f2fddb405eef4eee01427 Mon Sep 17 00:00:00 2001 From: plu Date: Tue, 2 Sep 2025 08:33:21 +0100 Subject: [PATCH 37/52] refactor the intensity type of flux into BaseSource class --- src/ansys/speos/core/source.py | 124 ++++++++++++++++----------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index 82a10ef76..0e76a56da 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -233,6 +233,68 @@ def value(self, value: float) -> None: """ self._radiant_flux.radiant_value = value + class Intensity: + """Intensity type of flux. + + By default, Intensity flux value is set to be 5 cd. + + Parameters + ---------- + intensity_flux : ansys.api.speos.source.v1.source_pb2.LuminousIntensity + LuminousIntensity protobuf object to modify. + default_values : bool + Uses default values when True. + stable_ctr : bool + Variable to indicate if usage is inside class scope + + Notes + ----- + **Do not instantiate this class yourself**, use set_flux_luminous_intensity + method available in Source classes. + """ + + def __init__( + self, + intensity_flux: source_pb2.LuminousIntensity, + default_values: bool = True, + stable_ctr: bool = False, + ): + if not stable_ctr: + msg = "Intensity class instantiated outside of class scope" + raise RuntimeError(msg) + self._intensity_flux = intensity_flux + + if default_values: + self.value = SOURCE.INTENSITY.VALUE + + @property + def value(self) -> float: + """Get intensity flux value. + + Returns + ------- + float + Intensity flux value. + + """ + return self._intensity_flux.luminous_intensity_value + + @value.setter + def value(self, value: float) -> None: + """Set intensity flux value. + + Parameters + ---------- + value: float + Intensity flux value. + + Returns + ------- + None + + """ + self._intensity_flux.luminous_intensity_value = value + class _Spectrum: def __init__( self, @@ -1124,68 +1186,6 @@ class SourceSurface(BaseSource): Uses default values when True. """ - class Intensity: - """Intensity type of flux. - - By default, Intensity flux value is set to be 5 cd. - - Parameters - ---------- - intensity_flux : ansys.api.speos.source.v1.source_pb2.LuminousIntensity - LuminousIntensity protobuf object to modify. - default_values : bool - Uses default values when True. - stable_ctr : bool - Variable to indicate if usage is inside class scope - - Notes - ----- - **Do not instantiate this class yourself**, use set_flux_luminous_intensity - method available in Source classes. - """ - - def __init__( - self, - intensity_flux: source_pb2.LuminousIntensity, - default_values: bool = True, - stable_ctr: bool = False, - ): - if not stable_ctr: - msg = "Intensity class instantiated outside of class scope" - raise RuntimeError(msg) - self._intensity_flux = intensity_flux - - if default_values: - self.value = SOURCE.INTENSITY.VALUE - - @property - def value(self) -> float: - """Get intensity flux value. - - Returns - ------- - float - Intensity flux value. - - """ - return self._intensity_flux.luminous_intensity_value - - @value.setter - def value(self, value: float) -> None: - """Set intensity flux value. - - Parameters - ---------- - value: float - Intensity flux value. - - Returns - ------- - None - - """ - self._intensity_flux.luminous_intensity_value = value - class ExitanceConstant: """Type of surface source existence : existence constant. From b86d00fbd37f1930590a48487d43ff29326ee9e5 Mon Sep 17 00:00:00 2001 From: plu Date: Tue, 2 Sep 2025 08:54:00 +0100 Subject: [PATCH 38/52] add test reference result from constants --- tests/core/test_source.py | 48 +++++++-------------------------------- 1 file changed, 8 insertions(+), 40 deletions(-) diff --git a/tests/core/test_source.py b/tests/core/test_source.py index 096a439ca..dfede87ab 100644 --- a/tests/core/test_source.py +++ b/tests/core/test_source.py @@ -28,6 +28,7 @@ import pytest from ansys.speos.core import GeoRef, Project, Speos +from ansys.speos.core.generic.constants import ORIGIN, SOURCE from ansys.speos.core.source import ( SourceAmbientNaturalLight, SourceLuminaire, @@ -51,20 +52,7 @@ def test_create_luminaire_source(speos: Speos): assert source1._spectrum._spectrum._spectrum.predefined.HasField("incandescent") assert source1._spectrum._spectrum._spectrum.name == "Luminaire.1.Spectrum" assert source1._source_instance.HasField("luminaire_properties") - assert source1._source_instance.luminaire_properties.axis_system == [ - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 1, - ] + assert source1._source_instance.luminaire_properties.axis_system == ORIGIN # intensity_file_uri source1.intensity_file_uri = Path(test_path) / "IES_C_DETECTOR.ies" @@ -177,7 +165,10 @@ def test_create_surface_source(speos: Speos): assert source1.source_template_link.get().HasField("surface") assert source1.source_template_link.get().surface.HasField("exitance_constant") assert source1.source_template_link.get().surface.HasField("luminous_flux") - assert source1.source_template_link.get().surface.luminous_flux.luminous_value == 683 + assert ( + source1.source_template_link.get().surface.luminous_flux.luminous_value + == SOURCE.LUMINOUS.VALUE + ) assert source1.source_template_link.get().surface.HasField("spectrum_guid") spectrum = speos.client[source1.source_template_link.get().surface.spectrum_guid] assert spectrum.get().name == "Surface.1.Spectrum" @@ -236,17 +227,7 @@ def test_create_surface_source(speos: Speos): assert source1.source_template_link.get().surface.exitance_variable.exitance_xmp_file_uri != "" assert source1.source_template_link.get().surface.HasField("spectrum_from_xmp_file") assert surface_properties.HasField("exitance_variable_properties") - assert surface_properties.exitance_variable_properties.axis_plane == [ - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 1, - 0, - ] + assert surface_properties.exitance_variable_properties.axis_plane == ORIGIN[:9] # Properties # exitance_variable axis_plane @@ -325,20 +306,7 @@ def test_create_rayfile_source(speos: Speos): name="Ray-file.1", ) assert source1._source_instance.HasField("rayfile_properties") - assert source1._source_instance.rayfile_properties.axis_system == [ - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 1, - ] + assert source1._source_instance.rayfile_properties.axis_system == ORIGIN assert source1._source_template.HasField("rayfile") assert source1._source_template.rayfile.HasField("flux_from_ray_file") assert source1._source_template.rayfile.HasField("spectrum_from_ray_file") From da7e5f0ebfee9b9acb9fc0bdb37ae7e56267aa92 Mon Sep 17 00:00:00 2001 From: plu Date: Tue, 2 Sep 2025 11:00:17 +0100 Subject: [PATCH 39/52] refactor the flux type class --- src/ansys/speos/core/source.py | 372 +++++++++++++++++---------------- tests/core/test_source.py | 6 +- 2 files changed, 192 insertions(+), 186 deletions(-) diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index 0e76a56da..bf50435a6 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -110,190 +110,131 @@ def __init__( self.source_template_link = self._project.client[source_instance.source_guid] self._reset() - class Luminous: - """Luminous type of flux. + class Flux: + """Different types of flux.""" - By default, Luminous flux value is set to be 683 lm. + class Luminous: + """Luminous type of flux. - Parameters - ---------- - luminous_flux : ansys.api.speos.source.v1.source_pb2.Luminous - Luminous protobuf object to modify. - default_values : bool - Uses default values when True. - stable_ctr : bool - Variable to indicate if usage is inside class scope - - Notes - ----- - **Do not instantiate this class yourself**, use set_flux_luminous method available in - Source classes. - """ - - def __init__( - self, - luminous_flux: source_pb2.Luminous, - default_values: bool = True, - stable_ctr: bool = False, - ): - if not stable_ctr: - msg = "Luminous class instantiated outside of class scope" - raise RuntimeError(msg) - self._luminous_flux = luminous_flux - - if default_values: - self.value = SOURCE.LUMINOUS.VALUE - - @property - def value(self) -> float: - """Get luminous flux value. - - Returns - ------- - float - Luminous flux value. - """ - return self._luminous_flux.luminous_value - - @value.setter - def value(self, value: float) -> None: - """Set luminous flux value. + By default, Luminous flux value is set to be 683 lm. Parameters ---------- - value: float - Luminous flux value. - - Returns - ------- - None - + luminous_flux : ansys.api.speos.source.v1.source_pb2.Luminous + Luminous protobuf object to modify. + default_values : bool + Uses default values when True. + stable_ctr : bool + Variable to indicate if usage is inside class scope + + Notes + ----- + **Do not instantiate this class yourself**, use set_flux_luminous method available in + Source classes. """ - self._luminous_flux.luminous_value = value - class Radiant: - """Radiant type of flux. + def __init__( + self, + luminous_flux: source_pb2.Luminous, + default_values: bool = True, + stable_ctr: bool = False, + ): + if not stable_ctr: + msg = "Luminous class instantiated outside of class scope" + raise RuntimeError(msg) + self._luminous_flux = luminous_flux - By default, Radiant flux value is set to be 1 W. + if default_values: + self.value = SOURCE.LUMINOUS.VALUE - Parameters - ---------- - radiant_flux : ansys.api.speos.source.v1.source_pb2.Radiant - Radiant protobuf object to modify. - default_values : bool - Uses default values when True. - stable_ctr : bool - Variable to indicate if usage is inside class scope + @property + def value(self) -> float: + """Get luminous flux value. - Notes - ----- - **Do not instantiate this class yourself**, use set_flux_radiant method available in - Source classes. - """ + Returns + ------- + float + Luminous flux value. + """ + return self._luminous_flux.luminous_value - def __init__( - self, - radiant_flux: source_pb2.Radiant, - default_values: bool = True, - stable_ctr: bool = False, - ): - if not stable_ctr: - msg = "Radiant class instantiated outside of class scope" - raise RuntimeError(msg) - self._radiant_flux = radiant_flux + @value.setter + def value(self, value: float) -> None: + """Set luminous flux value. - if default_values: - self.value = SOURCE.RADIANT.VALUE + Parameters + ---------- + value: float + Luminous flux value. - @property - def value(self) -> float: - """Get radiant flux value. + Returns + ------- + None - Returns - ------- - float - Radiant flux value. + """ + self._luminous_flux.luminous_value = value - """ - return self._radiant_flux.radiant_value + class Radiant: + """Radiant type of flux. - @value.setter - def value(self, value: float) -> None: - """Set radiant flux value. + By default, Radiant flux value is set to be 1 W. Parameters ---------- - value: float - Radiant flux value. - - Returns - ------- - None - + radiant_flux : ansys.api.speos.source.v1.source_pb2.Radiant + Radiant protobuf object to modify. + default_values : bool + Uses default values when True. + stable_ctr : bool + Variable to indicate if usage is inside class scope + + Notes + ----- + **Do not instantiate this class yourself**, use set_flux_radiant method available in + Source classes. """ - self._radiant_flux.radiant_value = value - class Intensity: - """Intensity type of flux. + def __init__( + self, + radiant_flux: source_pb2.Radiant, + default_values: bool = True, + stable_ctr: bool = False, + ): + if not stable_ctr: + msg = "Radiant class instantiated outside of class scope" + raise RuntimeError(msg) + self._radiant_flux = radiant_flux - By default, Intensity flux value is set to be 5 cd. + if default_values: + self.value = SOURCE.RADIANT.VALUE - Parameters - ---------- - intensity_flux : ansys.api.speos.source.v1.source_pb2.LuminousIntensity - LuminousIntensity protobuf object to modify. - default_values : bool - Uses default values when True. - stable_ctr : bool - Variable to indicate if usage is inside class scope + @property + def value(self) -> float: + """Get radiant flux value. - Notes - ----- - **Do not instantiate this class yourself**, use set_flux_luminous_intensity - method available in Source classes. - """ + Returns + ------- + float + Radiant flux value. - def __init__( - self, - intensity_flux: source_pb2.LuminousIntensity, - default_values: bool = True, - stable_ctr: bool = False, - ): - if not stable_ctr: - msg = "Intensity class instantiated outside of class scope" - raise RuntimeError(msg) - self._intensity_flux = intensity_flux + """ + return self._radiant_flux.radiant_value - if default_values: - self.value = SOURCE.INTENSITY.VALUE + @value.setter + def value(self, value: float) -> None: + """Set radiant flux value. - @property - def value(self) -> float: - """Get intensity flux value. + Parameters + ---------- + value: float + Radiant flux value. - Returns - ------- - float - Intensity flux value. + Returns + ------- + None - """ - return self._intensity_flux.luminous_intensity_value - - @value.setter - def value(self, value: float) -> None: - """Set intensity flux value. - - Parameters - ---------- - value: float - Intensity flux value. - - Returns - ------- - None - - """ - self._intensity_flux.luminous_intensity_value = value + """ + self._radiant_flux.radiant_value = value class _Spectrum: def __init__( @@ -698,7 +639,7 @@ def set_flux_from_intensity_file(self) -> SourceLuminaire: self._source_template.luminaire.flux_from_intensity_file.SetInParent() return self - def set_flux_luminous(self) -> SourceLuminaire.Luminous: + def set_flux_luminous(self) -> SourceLuminaire.Flux.Luminous: """Set luminous flux. Returns @@ -707,13 +648,13 @@ def set_flux_luminous(self) -> SourceLuminaire.Luminous: Luminaire luminous flux type source. """ if self._type is None and self._source_template.luminaire.HasField("luminous_flux"): - self._type = SourceLuminaire.Luminous( + self._type = SourceLuminaire.Flux.Luminous( luminous_flux=self._source_template.luminaire.luminous_flux, default_values=False, stable_ctr=True, ) - elif not isinstance(self._type, SourceLuminaire.Luminous): - self._type = SourceLuminaire.Luminous( + elif not isinstance(self._type, SourceLuminaire.Flux.Luminous): + self._type = SourceLuminaire.Flux.Luminous( luminous_flux=self._source_template.luminaire.luminous_flux, default_values=True, stable_ctr=True, @@ -722,7 +663,7 @@ def set_flux_luminous(self) -> SourceLuminaire.Luminous: self._type._luminous_flux = self._source_template.luminaire.luminous_flux return self._type - def set_flux_radiant(self) -> SourceLuminaire.Radiant: + def set_flux_radiant(self) -> SourceLuminaire.Flux.Radiant: """Set radiant flux. Returns @@ -731,13 +672,13 @@ def set_flux_radiant(self) -> SourceLuminaire.Radiant: Luminaire radiant flux type source. """ if self._type is None and self._source_template.luminaire.HasField("radiant_flux"): - self._type = SourceLuminaire.Radiant( + self._type = SourceLuminaire.Flux.Radiant( radiant_flux=self._source_template.luminaire.radiant_flux, default_values=False, stable_ctr=True, ) - elif not isinstance(self._type, SourceLuminaire.Radiant): - self._type = SourceLuminaire.Radiant( + elif not isinstance(self._type, SourceLuminaire.Flux.Radiant): + self._type = SourceLuminaire.Flux.Radiant( radiant_flux=self._source_template.luminaire.radiant_flux, default_values=True, stable_ctr=True, @@ -1025,7 +966,7 @@ def set_flux_from_ray_file(self) -> SourceRayFile: self._source_template.rayfile.flux_from_ray_file.SetInParent() return self - def set_flux_luminous(self) -> SourceRayFile.Luminous: + def set_flux_luminous(self) -> SourceRayFile.Flux.Luminous: """Set luminous flux. Returns @@ -1034,13 +975,13 @@ def set_flux_luminous(self) -> SourceRayFile.Luminous: Luminous flux type source. """ if self._type is None and self._source_template.rayfile.HasField("luminous_flux"): - self._type = SourceRayFile.Luminous( + self._type = SourceRayFile.Flux.Luminous( luminous_flux=self._source_template.rayfile.luminous_flux, default_values=False, stable_ctr=True, ) - elif not isinstance(self._type, SourceRayFile.Luminous): - self._type = SourceRayFile.Luminous( + elif not isinstance(self._type, SourceRayFile.Flux.Luminous): + self._type = SourceRayFile.Flux.Luminous( luminous_flux=self._source_template.rayfile.luminous_flux, default_values=True, stable_ctr=True, @@ -1049,7 +990,7 @@ def set_flux_luminous(self) -> SourceRayFile.Luminous: self._type._luminous_flux = self._source_template.rayfile.luminous_flux return self._type - def set_flux_radiant(self) -> SourceRayFile.Radiant: + def set_flux_radiant(self) -> SourceRayFile.Flux.Radiant: """Set radiant flux. Returns @@ -1058,13 +999,13 @@ def set_flux_radiant(self) -> SourceRayFile.Radiant: Radiant flux type source. """ if self._type is None and self._source_template.rayfile.HasField("radiant_flux"): - self._type = SourceRayFile.Radiant( + self._type = SourceRayFile.Flux.Radiant( radiant_flux=self._source_template.rayfile.radiant_flux, default_values=False, stable_ctr=True, ) - elif not isinstance(self._type, SourceRayFile.Radiant): - self._type = SourceRayFile.Radiant( + elif not isinstance(self._type, SourceRayFile.Flux.Radiant): + self._type = SourceRayFile.Flux.Radiant( radiant_flux=self._source_template.rayfile.radiant_flux, default_values=True, stable_ctr=True, @@ -1186,6 +1127,71 @@ class SourceSurface(BaseSource): Uses default values when True. """ + class Flux(BaseSource.Flux): + """Different types of flux including luminous flux of intensity.""" + + class Intensity: + """Intensity type of flux. + + By default, Intensity flux value is set to be 5 cd. + + Parameters + ---------- + intensity_flux : ansys.api.speos.source.v1.source_pb2.LuminousIntensity + LuminousIntensity protobuf object to modify. + default_values : bool + Uses default values when True. + stable_ctr : bool + Variable to indicate if usage is inside class scope + + Notes + ----- + **Do not instantiate this class yourself**, use set_flux_luminous_intensity + method available in Source classes. + """ + + def __init__( + self, + intensity_flux: source_pb2.LuminousIntensity, + default_values: bool = True, + stable_ctr: bool = False, + ): + if not stable_ctr: + msg = "Intensity class instantiated outside of class scope" + raise RuntimeError(msg) + self._intensity_flux = intensity_flux + + if default_values: + self.value = SOURCE.INTENSITY.VALUE + + @property + def value(self) -> float: + """Get intensity flux value. + + Returns + ------- + float + Intensity flux value. + + """ + return self._intensity_flux.luminous_intensity_value + + @value.setter + def value(self, value: float) -> None: + """Set intensity flux value. + + Parameters + ---------- + value: float + Intensity flux value. + + Returns + ------- + None + + """ + self._intensity_flux.luminous_intensity_value = value + class ExitanceConstant: """Type of surface source existence : existence constant. @@ -1474,7 +1480,7 @@ def set_flux_from_intensity_file(self) -> SourceSurface: self._source_template.surface.flux_from_intensity_file.SetInParent() return self - def set_flux_luminous(self) -> SourceSurface.Luminous: + def set_flux_luminous(self) -> SourceSurface.Flux.Luminous: """Set luminous flux. Returns @@ -1483,13 +1489,13 @@ def set_flux_luminous(self) -> SourceSurface.Luminous: Luminous flux type source. """ if self._flux_type is None and self._source_template.surface.HasField("luminous_flux"): - self._flux_type = SourceSurface.Luminous( + self._flux_type = SourceSurface.Flux.Luminous( luminous_flux=self._source_template.surface.luminous_flux, default_values=False, stable_ctr=True, ) - elif not isinstance(self._flux_type, SourceSurface.Luminous): - self._flux_type = SourceSurface.Luminous( + elif not isinstance(self._flux_type, SourceSurface.Flux.Luminous): + self._flux_type = SourceSurface.Flux.Luminous( luminous_flux=self._source_template.surface.luminous_flux, default_values=True, stable_ctr=True, @@ -1500,7 +1506,7 @@ def set_flux_luminous(self) -> SourceSurface.Luminous: # self._source_template.surface.luminous_flux.luminous_value = value # return self - def set_flux_radiant(self) -> SourceSurface.Radiant: + def set_flux_radiant(self) -> SourceSurface.Flux.Radiant: """Set radiant flux. Returns @@ -1509,13 +1515,13 @@ def set_flux_radiant(self) -> SourceSurface.Radiant: Radiant flux type source. """ if self._flux_type is None and self._source_template.surface.HasField("radiant_flux"): - self._flux_type = SourceSurface.Radiant( + self._flux_type = SourceSurface.Flux.Radiant( radiant_flux=self._source_template.surface.radiant_flux, default_values=False, stable_ctr=True, ) - elif not isinstance(self._flux_type, SourceSurface.Radiant): - self._flux_type = SourceSurface.Radiant( + elif not isinstance(self._flux_type, SourceSurface.Flux.Radiant): + self._flux_type = SourceSurface.Flux.Radiant( radiant_flux=self._source_template.surface.radiant_flux, default_values=True, stable_ctr=True, @@ -1526,7 +1532,7 @@ def set_flux_radiant(self) -> SourceSurface.Radiant: # self._source_template.surface.radiant_flux.radiant_value = value # return self - def set_flux_luminous_intensity(self) -> SourceSurface.Intensity: + def set_flux_luminous_intensity(self) -> Flux.Intensity: """Set intensity flux. Returns @@ -1537,13 +1543,13 @@ def set_flux_luminous_intensity(self) -> SourceSurface.Intensity: if self._flux_type is None and self._source_template.surface.HasField( "luminous_intensity_flux" ): - self._flux_type = SourceSurface.Intensity( + self._flux_type = SourceSurface.Flux.Intensity( intensity_flux=self._source_template.surface.luminous_intensity_flux, default_values=False, stable_ctr=True, ) - elif not isinstance(self._flux_type, SourceSurface.Intensity): - self._flux_type = SourceSurface.Intensity( + elif not isinstance(self._flux_type, SourceSurface.Flux.Intensity): + self._flux_type = SourceSurface.Flux.Intensity( intensity_flux=self._source_template.surface.luminous_intensity_flux, default_values=True, stable_ctr=True, diff --git a/tests/core/test_source.py b/tests/core/test_source.py index dfede87ab..1401e1ffc 100644 --- a/tests/core/test_source.py +++ b/tests/core/test_source.py @@ -125,14 +125,14 @@ def test_create_luminaire_source(speos: Speos): ] with pytest.raises(RuntimeError, match="Luminous class instantiated outside of class scope"): - SourceLuminaire.Luminous( + SourceLuminaire.Flux.Luminous( luminous_flux=source1._source_template.luminaire.luminous_flux, default_values=True, stable_ctr=False, ) with pytest.raises(RuntimeError, match="Radiant class instantiated outside of class scope"): - SourceLuminaire.Radiant( + SourceLuminaire.Flux.Radiant( radiant_flux=source1._source_template.luminaire.radiant_flux, default_values=True, stable_ctr=False, @@ -267,7 +267,7 @@ def test_create_surface_source(speos: Speos): assert len(surface_properties.exitance_constant_properties.geo_paths) == 0 with pytest.raises(RuntimeError, match="Intensity class instantiated outside of class scope"): - SourceSurface.Intensity( + SourceSurface.Flux.Intensity( intensity_flux=source1._source_template.surface.luminous_intensity_flux, default_values=True, stable_ctr=False, From 4786dbaecc29ea5dac093be3ab744eb17212edb5 Mon Sep 17 00:00:00 2001 From: plu Date: Thu, 4 Sep 2025 13:15:48 +0100 Subject: [PATCH 40/52] refactor the flux class and corresponding unittests --- src/ansys/speos/core/source.py | 748 +++++++++++++++++++-------------- tests/core/test_source.py | 92 ++-- 2 files changed, 500 insertions(+), 340 deletions(-) diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index bf50435a6..c9b987c34 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -111,130 +111,222 @@ def __init__( self._reset() class Flux: - """Different types of flux.""" + """Type of flux. - class Luminous: - """Luminous type of flux. + By default, Luminous flux value is set with value 683 lm. - By default, Luminous flux value is set to be 683 lm. - - Parameters - ---------- - luminous_flux : ansys.api.speos.source.v1.source_pb2.Luminous - Luminous protobuf object to modify. - default_values : bool - Uses default values when True. - stable_ctr : bool - Variable to indicate if usage is inside class scope - - Notes - ----- - **Do not instantiate this class yourself**, use set_flux_luminous method available in - Source classes. - """ - - def __init__( - self, - luminous_flux: source_pb2.Luminous, - default_values: bool = True, - stable_ctr: bool = False, - ): - if not stable_ctr: - msg = "Luminous class instantiated outside of class scope" - raise RuntimeError(msg) - self._luminous_flux = luminous_flux - - if default_values: - self.value = SOURCE.LUMINOUS.VALUE - - @property - def value(self) -> float: - """Get luminous flux value. - - Returns - ------- - float - Luminous flux value. - """ - return self._luminous_flux.luminous_value + Parameters + ---------- + flux : ansys.api.speos.source.v1.source_pb2 + flux protobuf object to modify. + default_values : bool + Uses default values when True. + stable_ctr : bool + Variable to indicate if usage is inside class scope - @value.setter - def value(self, value: float) -> None: - """Set luminous flux value. + Notes + ----- + **Do not instantiate this class yourself**, use set_flux method available in source classes. + """ - Parameters - ---------- - value: float - Luminous flux value. + # class Luminous: + # """Luminous type of flux. + # + # By default, Luminous flux value is set to be 683 lm. + # + # Parameters + # ---------- + # luminous_flux : ansys.api.speos.source.v1.source_pb2.Luminous + # Luminous protobuf object to modify. + # default_values : bool + # Uses default values when True. + # stable_ctr : bool + # Variable to indicate if usage is inside class scope + # + # Notes + # ----- + # **Do not instantiate this class yourself**, use set_flux_luminous method available in + # Source classes. + # """ + # + # def __init__( + # self, + # luminous_flux: source_pb2.Luminous, + # default_values: bool = True, + # stable_ctr: bool = False, + # ): + # if not stable_ctr: + # msg = "Luminous class instantiated outside of class scope" + # raise RuntimeError(msg) + # self._luminous_flux = luminous_flux + # + # if default_values: + # self.value = SOURCE.LUMINOUS.VALUE + # + # @property + # def value(self) -> float: + # """Get luminous flux value. + # + # Returns + # ------- + # float + # Luminous flux value. + # """ + # return self._luminous_flux.luminous_value + # + # @value.setter + # def value(self, value: float) -> None: + # """Set luminous flux value. + # + # Parameters + # ---------- + # value: float + # Luminous flux value. + # + # Returns + # ------- + # None + # + # """ + # self._luminous_flux.luminous_value = value + # + # class Radiant: + # """Radiant type of flux. + # + # By default, Radiant flux value is set to be 1 W. + # + # Parameters + # ---------- + # radiant_flux : ansys.api.speos.source.v1.source_pb2.Radiant + # Radiant protobuf object to modify. + # default_values : bool + # Uses default values when True. + # stable_ctr : bool + # Variable to indicate if usage is inside class scope + # + # Notes + # ----- + # **Do not instantiate this class yourself**, use set_flux_radiant method available in + # Source classes. + # """ + # + # def __init__( + # self, + # radiant_flux: source_pb2.Radiant, + # default_values: bool = True, + # stable_ctr: bool = False, + # ): + # if not stable_ctr: + # msg = "Radiant class instantiated outside of class scope" + # raise RuntimeError(msg) + # self._radiant_flux = radiant_flux + # + # if default_values: + # self.value = SOURCE.RADIANT.VALUE + # + # @property + # def value(self) -> float: + # """Get radiant flux value. + # + # Returns + # ------- + # float + # Radiant flux value. + # + # """ + # return self._radiant_flux.radiant_value + # + # @value.setter + # def value(self, value: float) -> None: + # """Set radiant flux value. + # + # Parameters + # ---------- + # value: float + # Radiant flux value. + # + # Returns + # ------- + # None + # + # """ + # self._radiant_flux.radiant_value = value - Returns - ------- - None + def __init__( + self, + flux: source_pb2, + default_values: bool = True, + stable_ctr: bool = False, + ): + if not stable_ctr: + msg = "Flux class instantiated outside of class scope" + raise RuntimeError(msg) + self._flux = flux + self._flux_type = None - """ - self._luminous_flux.luminous_value = value + if default_values: + self.set_luminous() + self.value = SOURCE.LUMINOUS.VALUE - class Radiant: - """Radiant type of flux. + def set_luminous(self) -> None: + """Set flux type luminous. - By default, Radiant flux value is set to be 1 W. + Returns + ------- + None - Parameters - ---------- - radiant_flux : ansys.api.speos.source.v1.source_pb2.Radiant - Radiant protobuf object to modify. - default_values : bool - Uses default values when True. - stable_ctr : bool - Variable to indicate if usage is inside class scope - - Notes - ----- - **Do not instantiate this class yourself**, use set_flux_radiant method available in - Source classes. """ + self._flux_type = self._flux.luminous_flux - def __init__( - self, - radiant_flux: source_pb2.Radiant, - default_values: bool = True, - stable_ctr: bool = False, - ): - if not stable_ctr: - msg = "Radiant class instantiated outside of class scope" - raise RuntimeError(msg) - self._radiant_flux = radiant_flux + def set_radiant(self) -> None: + """Set flux type radiant. - if default_values: - self.value = SOURCE.RADIANT.VALUE + Returns + ------- + None - @property - def value(self) -> float: - """Get radiant flux value. + """ + self._flux_type = self._flux.radiant_flux - Returns - ------- - float - Radiant flux value. + @property + def value(self) -> float: + """Get flux type's value. - """ - return self._radiant_flux.radiant_value + Returns + ------- + float + value of the flux. - @value.setter - def value(self, value: float) -> None: - """Set radiant flux value. + """ + match self._flux_type.__name__: + case "Luminous": + return self._flux_type.luminous_value + case "Radiant": + return self._flux_type.radiant_value + case _: + raise ValueError(f"Unsupported flux type: {self._flux_type.__name__}") + + @value.setter + def value(self, value: float) -> None: + """Set flux type's value. - Parameters - ---------- - value: float - Radiant flux value. + Parameters + ---------- + value: float + Value of the flux. - Returns - ------- - None + Returns + ------- + None - """ - self._radiant_flux.radiant_value = value + """ + match self._flux_type.__name__: + case "Luminous": + self._flux_type.luminous_value = value + case "Radiant": + self._flux_type.radiant_value = value + case _: + raise ValueError(f"Unsupported flux type: {self._flux_type.__name__}") class _Spectrum: def __init__( @@ -639,54 +731,73 @@ def set_flux_from_intensity_file(self) -> SourceLuminaire: self._source_template.luminaire.flux_from_intensity_file.SetInParent() return self - def set_flux_luminous(self) -> SourceLuminaire.Flux.Luminous: - """Set luminous flux. + def set_flux(self) -> SourceLuminaire.Flux: + """Set flux of the luminaire source. Returns ------- - ansys.speos.core.source.SourceLuminaire.Luminous - Luminaire luminous flux type source. - """ - if self._type is None and self._source_template.luminaire.HasField("luminous_flux"): - self._type = SourceLuminaire.Flux.Luminous( - luminous_flux=self._source_template.luminaire.luminous_flux, - default_values=False, - stable_ctr=True, - ) - elif not isinstance(self._type, SourceLuminaire.Flux.Luminous): - self._type = SourceLuminaire.Flux.Luminous( - luminous_flux=self._source_template.luminaire.luminous_flux, - default_values=True, - stable_ctr=True, - ) - elif self._type._luminous_flux is not self._source_template.luminaire.luminous_flux: - self._type._luminous_flux = self._source_template.luminaire.luminous_flux - return self._type + ansys.speos.core.source.SourceLuminaire.Flux + flux object of the source - def set_flux_radiant(self) -> SourceLuminaire.Flux.Radiant: - """Set radiant flux. - - Returns - ------- - ansys.speos.core.source.SourceLuminaire.Radiant - Luminaire radiant flux type source. """ - if self._type is None and self._source_template.luminaire.HasField("radiant_flux"): - self._type = SourceLuminaire.Flux.Radiant( - radiant_flux=self._source_template.luminaire.radiant_flux, - default_values=False, - stable_ctr=True, - ) - elif not isinstance(self._type, SourceLuminaire.Flux.Radiant): - self._type = SourceLuminaire.Flux.Radiant( - radiant_flux=self._source_template.luminaire.radiant_flux, + if self._type is None: + self._type = self.Flux( + flux=self._source_template.luminaire, default_values=True, stable_ctr=True, ) - elif self._type._radiant_flux is not self._source_template.luminaire.radiant_flux: - self._type._radiant_flux = self._source_template.luminaire.radiant_flux + elif self._type._flux is not self._source_template.luminaire: + self._type._flux = self._source_template.luminaire return self._type + # def set_flux_luminous(self) -> SourceLuminaire.Flux.Luminous: + # """Set luminous flux. + # + # Returns + # ------- + # ansys.speos.core.source.SourceLuminaire.Luminous + # Luminaire luminous flux type source. + # """ + # if self._type is None and self._source_template.luminaire.HasField("luminous_flux"): + # self._type = SourceLuminaire.Flux.Luminous( + # luminous_flux=self._source_template.luminaire.luminous_flux, + # default_values=False, + # stable_ctr=True, + # ) + # elif not isinstance(self._type, SourceLuminaire.Flux.Luminous): + # self._type = SourceLuminaire.Flux.Luminous( + # luminous_flux=self._source_template.luminaire.luminous_flux, + # default_values=True, + # stable_ctr=True, + # ) + # elif self._type._luminous_flux is not self._source_template.luminaire.luminous_flux: + # self._type._luminous_flux = self._source_template.luminaire.luminous_flux + # return self._type + # + # def set_flux_radiant(self) -> SourceLuminaire.Flux.Radiant: + # """Set radiant flux. + # + # Returns + # ------- + # ansys.speos.core.source.SourceLuminaire.Radiant + # Luminaire radiant flux type source. + # """ + # if self._type is None and self._source_template.luminaire.HasField("radiant_flux"): + # self._type = SourceLuminaire.Flux.Radiant( + # radiant_flux=self._source_template.luminaire.radiant_flux, + # default_values=False, + # stable_ctr=True, + # ) + # elif not isinstance(self._type, SourceLuminaire.Flux.Radiant): + # self._type = SourceLuminaire.Flux.Radiant( + # radiant_flux=self._source_template.luminaire.radiant_flux, + # default_values=True, + # stable_ctr=True, + # ) + # elif self._type._radiant_flux is not self._source_template.luminaire.radiant_flux: + # self._type._radiant_flux = self._source_template.luminaire.radiant_flux + # return self._type + @property def intensity_file_uri(self) -> str: """Get intensity file. @@ -966,54 +1077,73 @@ def set_flux_from_ray_file(self) -> SourceRayFile: self._source_template.rayfile.flux_from_ray_file.SetInParent() return self - def set_flux_luminous(self) -> SourceRayFile.Flux.Luminous: - """Set luminous flux. + def set_flux(self) -> SourceRayFile.Flux: + """Set flux of the Rayfile source. Returns ------- - ansys.speos.core.source.SourceRayFile.Luminous - Luminous flux type source. - """ - if self._type is None and self._source_template.rayfile.HasField("luminous_flux"): - self._type = SourceRayFile.Flux.Luminous( - luminous_flux=self._source_template.rayfile.luminous_flux, - default_values=False, - stable_ctr=True, - ) - elif not isinstance(self._type, SourceRayFile.Flux.Luminous): - self._type = SourceRayFile.Flux.Luminous( - luminous_flux=self._source_template.rayfile.luminous_flux, - default_values=True, - stable_ctr=True, - ) - elif self._type._luminous_flux is not self._source_template.rayfile.luminous_flux: - self._type._luminous_flux = self._source_template.rayfile.luminous_flux - return self._type + ansys.speos.core.source.SourceRayFile.Flux + flux object of the source - def set_flux_radiant(self) -> SourceRayFile.Flux.Radiant: - """Set radiant flux. - - Returns - ------- - ansys.speos.core.source.SourceRayFile.Radiant - Radiant flux type source. """ - if self._type is None and self._source_template.rayfile.HasField("radiant_flux"): - self._type = SourceRayFile.Flux.Radiant( - radiant_flux=self._source_template.rayfile.radiant_flux, - default_values=False, - stable_ctr=True, - ) - elif not isinstance(self._type, SourceRayFile.Flux.Radiant): - self._type = SourceRayFile.Flux.Radiant( - radiant_flux=self._source_template.rayfile.radiant_flux, + if self._type is None: + self._type = self.Flux( + flux=self._source_template.rayfile, default_values=True, stable_ctr=True, ) - elif self._type._radiant_flux is not self._source_template.rayfile.radiant_flux: - self._type._radiant_flux = self._source_template.rayfile.radiant_flux + elif self._type._flux is not self._source_template.rayfile: + self._type._flux = self._source_template.rayfile return self._type + # def set_flux_luminous(self) -> SourceRayFile.Flux.Luminous: + # """Set luminous flux. + # + # Returns + # ------- + # ansys.speos.core.source.SourceRayFile.Luminous + # Luminous flux type source. + # """ + # if self._type is None and self._source_template.rayfile.HasField("luminous_flux"): + # self._type = SourceRayFile.Flux.Luminous( + # luminous_flux=self._source_template.rayfile.luminous_flux, + # default_values=False, + # stable_ctr=True, + # ) + # elif not isinstance(self._type, SourceRayFile.Flux.Luminous): + # self._type = SourceRayFile.Flux.Luminous( + # luminous_flux=self._source_template.rayfile.luminous_flux, + # default_values=True, + # stable_ctr=True, + # ) + # elif self._type._luminous_flux is not self._source_template.rayfile.luminous_flux: + # self._type._luminous_flux = self._source_template.rayfile.luminous_flux + # return self._type + # + # def set_flux_radiant(self) -> SourceRayFile.Flux.Radiant: + # """Set radiant flux. + # + # Returns + # ------- + # ansys.speos.core.source.SourceRayFile.Radiant + # Radiant flux type source. + # """ + # if self._type is None and self._source_template.rayfile.HasField("radiant_flux"): + # self._type = SourceRayFile.Flux.Radiant( + # radiant_flux=self._source_template.rayfile.radiant_flux, + # default_values=False, + # stable_ctr=True, + # ) + # elif not isinstance(self._type, SourceRayFile.Flux.Radiant): + # self._type = SourceRayFile.Flux.Radiant( + # radiant_flux=self._source_template.rayfile.radiant_flux, + # default_values=True, + # stable_ctr=True, + # ) + # elif self._type._radiant_flux is not self._source_template.rayfile.radiant_flux: + # self._type._radiant_flux = self._source_template.rayfile.radiant_flux + # return self._type + def set_spectrum_from_ray_file(self) -> SourceRayFile: """Take spectrum from ray file provided. @@ -1130,67 +1260,133 @@ class SourceSurface(BaseSource): class Flux(BaseSource.Flux): """Different types of flux including luminous flux of intensity.""" - class Intensity: - """Intensity type of flux. - - By default, Intensity flux value is set to be 5 cd. - - Parameters - ---------- - intensity_flux : ansys.api.speos.source.v1.source_pb2.LuminousIntensity - LuminousIntensity protobuf object to modify. - default_values : bool - Uses default values when True. - stable_ctr : bool - Variable to indicate if usage is inside class scope - - Notes - ----- - **Do not instantiate this class yourself**, use set_flux_luminous_intensity - method available in Source classes. - """ + # + # class Intensity: + # """Intensity type of flux. + # + # By default, Intensity flux value is set to be 5 cd. + # + # Parameters + # ---------- + # intensity_flux : ansys.api.speos.source.v1.source_pb2.LuminousIntensity + # LuminousIntensity protobuf object to modify. + # default_values : bool + # Uses default values when True. + # stable_ctr : bool + # Variable to indicate if usage is inside class scope + # + # Notes + # ----- + # **Do not instantiate this class yourself**, use set_flux_luminous_intensity + # method available in Source classes. + # """ + # + # def __init__( + # self, + # intensity_flux: source_pb2.LuminousIntensity, + # default_values: bool = True, + # stable_ctr: bool = False, + # ): + # if not stable_ctr: + # msg = "Intensity class instantiated outside of class scope" + # raise RuntimeError(msg) + # self._intensity_flux = intensity_flux + # + # if default_values: + # self.value = SOURCE.INTENSITY.VALUE + # + # @property + # def value(self) -> float: + # """Get intensity flux value. + # + # Returns + # ------- + # float + # Intensity flux value. + # + # """ + # return self._intensity_flux.luminous_intensity_value + # + # @value.setter + # def value(self, value: float) -> None: + # """Set intensity flux value. + # + # Parameters + # ---------- + # value: float + # Intensity flux value. + # + # Returns + # ------- + # None + # + # """ + # self._intensity_flux.luminous_intensity_value = value + # + def __init__( + self, + flux: source_pb2, + default_values: bool = True, + stable_ctr: bool = False, + ): + if not stable_ctr: + msg = "Flux class instantiated outside of class scope" + raise RuntimeError(msg) + super().__init__(flux, default_values, stable_ctr) - def __init__( - self, - intensity_flux: source_pb2.LuminousIntensity, - default_values: bool = True, - stable_ctr: bool = False, - ): - if not stable_ctr: - msg = "Intensity class instantiated outside of class scope" - raise RuntimeError(msg) - self._intensity_flux = intensity_flux + def set_luminous_intensity(self): + """Set flux type luminous intensity. - if default_values: - self.value = SOURCE.INTENSITY.VALUE + Returns + ------- + None - @property - def value(self) -> float: - """Get intensity flux value. + """ + self._flux_type = self._flux.luminous_intensity_flux - Returns - ------- - float - Intensity flux value. + @property + def value(self) -> float: + """Get flux type's value. - """ - return self._intensity_flux.luminous_intensity_value + Returns + ------- + float + Flux type value. - @value.setter - def value(self, value: float) -> None: - """Set intensity flux value. + """ + match self._flux_type.__name__: + case "Luminous": + return self._flux_type.luminous_value + case "Radiant": + return self._flux_type.radiant_value + case "LuminousIntensity": + return self._flux_type.luminous_intensity_value + case _: + raise ValueError(f"Unsupported flux type: {self._flux_type.__name__}") + + @value.setter + def value(self, value: float) -> None: + """Set flux type's value. - Parameters - ---------- - value: float - Intensity flux value. + Parameters + ---------- + value: float + Value of the flux. - Returns - ------- - None + Returns + ------- + None - """ - self._intensity_flux.luminous_intensity_value = value + """ + match self._flux_type.__name__: + case "Luminous": + self._flux_type.luminous_value = value + case "Radiant": + self._flux_type.radiant_value = value + case "LuminousIntensity": + self._flux_type.luminous_intensity_value = value + case _: + raise ValueError(f"Unsupported flux type: {self._flux_type.__name__}") class ExitanceConstant: """Type of surface source existence : existence constant. @@ -1420,7 +1616,9 @@ def __init__( if default_values: # Default values - self.set_flux_luminous() + self.set_flux().set_luminous() + self.set_flux().value = SOURCE.LUMINOUS.VALUE + # self.set_flux_luminous() self.set_exitance_constant().geometries = [] self.set_intensity() self.set_spectrum() @@ -1480,88 +1678,24 @@ def set_flux_from_intensity_file(self) -> SourceSurface: self._source_template.surface.flux_from_intensity_file.SetInParent() return self - def set_flux_luminous(self) -> SourceSurface.Flux.Luminous: - """Set luminous flux. + def set_flux(self) -> SourceSurface.Flux: + """Set flux of the Surface source. Returns ------- - ansys.speos.core.source.SourceSurface.Luminous - Luminous flux type source. - """ - if self._flux_type is None and self._source_template.surface.HasField("luminous_flux"): - self._flux_type = SourceSurface.Flux.Luminous( - luminous_flux=self._source_template.surface.luminous_flux, - default_values=False, - stable_ctr=True, - ) - elif not isinstance(self._flux_type, SourceSurface.Flux.Luminous): - self._flux_type = SourceSurface.Flux.Luminous( - luminous_flux=self._source_template.surface.luminous_flux, - default_values=True, - stable_ctr=True, - ) - elif self._flux_type._luminous_flux is not self._source_template.surface.luminous_flux: - self._flux_type._luminous_flux = self._source_template.surface.luminous_flux - return self._flux_type - # self._source_template.surface.luminous_flux.luminous_value = value - # return self - - def set_flux_radiant(self) -> SourceSurface.Flux.Radiant: - """Set radiant flux. + ansys.speos.core.source.SourceSurface.Flux + flux object of the source - Returns - ------- - ansys.speos.core.source.SourceSurface.Radiant - Radiant flux type source. """ - if self._flux_type is None and self._source_template.surface.HasField("radiant_flux"): - self._flux_type = SourceSurface.Flux.Radiant( - radiant_flux=self._source_template.surface.radiant_flux, - default_values=False, - stable_ctr=True, - ) - elif not isinstance(self._flux_type, SourceSurface.Flux.Radiant): - self._flux_type = SourceSurface.Flux.Radiant( - radiant_flux=self._source_template.surface.radiant_flux, - default_values=True, - stable_ctr=True, - ) - elif self._flux_type._radiant_flux is not self._source_template.surface.radiant_flux: - self._flux_type._radiant_flux = self._source_template.surface.radiant_flux - return self._flux_type - # self._source_template.surface.radiant_flux.radiant_value = value - # return self - - def set_flux_luminous_intensity(self) -> Flux.Intensity: - """Set intensity flux. - - Returns - ------- - ansys.speos.core.source.SourceSurface.Intensity - Intensity flux type source. - """ - if self._flux_type is None and self._source_template.surface.HasField( - "luminous_intensity_flux" - ): - self._flux_type = SourceSurface.Flux.Intensity( - intensity_flux=self._source_template.surface.luminous_intensity_flux, - default_values=False, - stable_ctr=True, - ) - elif not isinstance(self._flux_type, SourceSurface.Flux.Intensity): - self._flux_type = SourceSurface.Flux.Intensity( - intensity_flux=self._source_template.surface.luminous_intensity_flux, + if self._flux_type is None: + self._flux_type = self.Flux( + flux=self._source_template.surface, default_values=True, stable_ctr=True, ) - elif ( - self._flux_type._intensity_flux - is not self._source_template.surface.luminous_intensity_flux - ): - self._flux_type._intensity_flux = self._source_template.surface.luminous_intensity_flux + elif self._flux_type._flux is not self._source_template.surface: + self._flux_type._flux = self._source_template.surface return self._flux_type - # self._source_template.surface.luminous_intensity_flux.luminous_intensity_value = value - # return self def set_intensity(self) -> intensity.Intensity: """Set intensity. diff --git a/tests/core/test_source.py b/tests/core/test_source.py index 1401e1ffc..56ddf9468 100644 --- a/tests/core/test_source.py +++ b/tests/core/test_source.py @@ -69,16 +69,22 @@ def test_create_luminaire_source(speos: Speos): assert spectrum.get().predefined.HasField("halogen") # flux luminous_flux - source1.set_flux_luminous().value = 650 + source1.set_flux().set_luminous() + source1.set_flux().value = 650 + # source1.set_flux_luminous().value = 650 source1.commit() - assert source1.set_flux_luminous().value == 650 + assert source1.set_flux().value == 650 + # assert source1.set_flux_luminous().value == 650 assert source1.source_template_link.get().luminaire.HasField("luminous_flux") assert source1.source_template_link.get().luminaire.luminous_flux.luminous_value == 650 # flux radiant_flux - source1.set_flux_radiant().value = 1.2 + source1.set_flux().set_radiant() + source1.set_flux().value = 1.2 + # source1.set_flux_radiant().value = 1.2 source1.commit() - assert source1.set_flux_radiant().value == 1.2 + assert source1.set_flux().value == 1.2 + # assert source1.set_flux_radiant().value == 1.2 assert source1.source_template_link.get().luminaire.HasField("radiant_flux") assert source1.source_template_link.get().luminaire.radiant_flux.radiant_value == 1.2 @@ -124,16 +130,9 @@ def test_create_luminaire_source(speos: Speos): 1, ] - with pytest.raises(RuntimeError, match="Luminous class instantiated outside of class scope"): - SourceLuminaire.Flux.Luminous( - luminous_flux=source1._source_template.luminaire.luminous_flux, - default_values=True, - stable_ctr=False, - ) - - with pytest.raises(RuntimeError, match="Radiant class instantiated outside of class scope"): - SourceLuminaire.Flux.Radiant( - radiant_flux=source1._source_template.luminaire.radiant_flux, + with pytest.raises(RuntimeError, match="Flux class instantiated outside of class scope"): + SourceLuminaire.Flux( + flux=source1._source_template.luminaire, default_values=True, stable_ctr=False, ) @@ -193,21 +192,30 @@ def test_create_surface_source(speos: Speos): assert surface_properties.intensity_properties.library_properties.HasField("axis_system") # luminous_flux - source1.set_flux_luminous().value = 630 + source1.set_flux().set_luminous() + source1.set_flux().value = 630 + # source1.set_flux_luminous().value = 630 source1.commit() + assert source1.set_flux().value == 630 assert source1.source_template_link.get().surface.HasField("luminous_flux") assert source1.source_template_link.get().surface.luminous_flux.luminous_value == 630 # radiant_flux - source1.set_flux_radiant().value = 1.1 + source1.set_flux().set_radiant() + source1.set_flux().value = 1.1 + # source1.set_flux_radiant().value = 1.1 source1.commit() + assert source1.set_flux().value == 1.1 assert source1.source_template_link.get().surface.HasField("radiant_flux") assert source1.source_template_link.get().surface.radiant_flux.radiant_value == 1.1 # luminous_intensity_flux - source1.set_flux_luminous_intensity().value = 5.5 + source1.set_flux().set_luminous_intensity() + source1.set_flux().value = 5.5 + # source1.set_flux_luminous_intensity().value = 5.5 source1.commit() - assert source1.set_flux_luminous_intensity().value == 5.5 + assert source1.set_flux().value == 5.5 + # assert source1.set_flux_luminous_intensity().value == 5.5 assert source1.source_template_link.get().surface.HasField("luminous_intensity_flux") assert ( source1.source_template_link.get().surface.luminous_intensity_flux.luminous_intensity_value @@ -266,9 +274,9 @@ def test_create_surface_source(speos: Speos): assert surface_properties.HasField("exitance_constant_properties") assert len(surface_properties.exitance_constant_properties.geo_paths) == 0 - with pytest.raises(RuntimeError, match="Intensity class instantiated outside of class scope"): - SourceSurface.Flux.Intensity( - intensity_flux=source1._source_template.surface.luminous_intensity_flux, + with pytest.raises(RuntimeError, match="Flux class instantiated outside of class scope"): + SourceSurface.Flux( + flux=source1._source_template.surface, default_values=True, stable_ctr=False, ) @@ -323,16 +331,22 @@ def test_create_rayfile_source(speos: Speos): assert source1.source_template_link.get().rayfile.HasField("spectrum_from_ray_file") # luminous_flux - source1.set_flux_luminous().value = 641 + source1.set_flux().set_luminous() + source1.set_flux().value = 641 + # source1.set_flux_luminous().value = 641 source1.commit() - assert source1.set_flux_luminous().value == 641 + assert source1.set_flux().value == 641 + # assert source1.set_flux_luminous().value == 641 assert source1.source_template_link.get().rayfile.HasField("luminous_flux") assert source1.source_template_link.get().rayfile.luminous_flux.luminous_value == 641 # radiant_flux - source1.set_flux_radiant().value = 1.3 + source1.set_flux().set_radiant() + source1.set_flux().value = 1.3 + # source1.set_flux_radiant().value = 1.3 source1.commit() - assert source1.set_flux_radiant().value == 1.3 + assert source1.set_flux().value == 1.3 + # assert source1.set_flux_radiant().value == 1.3 assert source1.source_template_link.get().rayfile.HasField("radiant_flux") assert source1.source_template_link.get().rayfile.radiant_flux.radiant_value == 1.3 @@ -660,7 +674,9 @@ def test_reset_source(speos: Speos): assert p.scene_link.get().sources[0].HasField("rayfile_properties") # Change local data (on template and on instance) - source1.set_flux_radiant().value = 3.5 # template + source1.set_flux().set_radiant() + source1.set_flux().value = 3.5 + # source1.set_flux_radiant().value = 3.5 # template source1.set_exit_geometries().geometries = [ GeoRef.from_native_link("TheBodyB/TheFaceB1") ] # instance @@ -691,7 +707,8 @@ def test_luminaire_modify_after_reset(speos: Speos): # Create + commit source = SourceLuminaire(project=p, name="Luminaire.1") source.intensity_file_uri = Path(test_path) / "IES_C_DETECTOR.ies" - source.set_flux_luminous() + source.set_flux().set_luminous() + # source.set_flux_luminous() source.commit() # Ask for reset @@ -699,9 +716,12 @@ def test_luminaire_modify_after_reset(speos: Speos): # Modify after a reset # Template - assert source.set_flux_luminous().value == 683 + assert source.set_flux().value == 683 + # assert source.set_flux_luminous().value == 683 assert source._source_template.luminaire.luminous_flux.luminous_value == 683 - source.set_flux_luminous().value = 500 + source.set_flux().set_luminous() + source.set_flux().value = 500 + # source.set_flux_luminous().value = 500 assert source._source_template.luminaire.luminous_flux.luminous_value == 500 # Intermediate class for spectrum @@ -749,7 +769,8 @@ def test_rayfile_modify_after_reset(speos: Speos): # Create + commit source = SourceRayFile(project=p, name="1") - source.set_flux_luminous() + # source.set_flux_luminous() + source.set_flux().set_luminous() source.ray_file_uri = Path(test_path) / "RaysWithoutSpectralData.RAY" source.set_spectrum() source.commit() @@ -760,7 +781,9 @@ def test_rayfile_modify_after_reset(speos: Speos): # Modify after a reset # Template assert source._source_template.rayfile.luminous_flux.luminous_value == 683 - source.set_flux_luminous().value = 500 + source.set_flux().set_luminous() + source.set_flux().value = 500 + # source.set_flux_luminous().value = 500 assert source._source_template.rayfile.luminous_flux.luminous_value == 500 # Intermediate class for spectrum @@ -808,7 +831,8 @@ def test_surface_modify_after_reset(speos: Speos): # Create + commit source = SourceSurface(project=p, name="Surface.2") - source.set_flux_luminous() + # source.set_flux_luminous() + source.set_flux().set_luminous() source.set_spectrum_from_xmp_file() source.set_exitance_variable().xmp_file_uri = ( Path(test_path) / "PROJECT.Direct-no-Ray.Irradiance Ray Spectral.xmp" @@ -821,7 +845,9 @@ def test_surface_modify_after_reset(speos: Speos): # Modify after a reset # Template assert source._source_template.surface.luminous_flux.luminous_value == 683 - source.set_flux_luminous().value = 500 + source.set_flux().set_luminous() + source.set_flux().value = 500 + # source.set_flux_luminous().value = 500 assert source._source_template.surface.luminous_flux.luminous_value == 500 # Intermediate class for spectrum From 8512e071eabfbbbc8ee25757badbf3ce4154b69d Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:17:56 +0000 Subject: [PATCH 41/52] chore: adding changelog file 690.added.md [dependabot-skip] --- doc/changelog.d/690.added.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelog.d/690.added.md b/doc/changelog.d/690.added.md index fcf3ce47f..ca7be60e0 100644 --- a/doc/changelog.d/690.added.md +++ b/doc/changelog.d/690.added.md @@ -1 +1 @@ -Refactor source class \ No newline at end of file +Refactor source class From 58e6075147158e0431af889a1cc32730084e1777 Mon Sep 17 00:00:00 2001 From: plu Date: Thu, 4 Sep 2025 13:20:02 +0100 Subject: [PATCH 42/52] clean the comments --- src/ansys/speos/core/source.py | 282 --------------------------------- 1 file changed, 282 deletions(-) diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index c9b987c34..73d71e9ff 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -129,129 +129,6 @@ class Flux: **Do not instantiate this class yourself**, use set_flux method available in source classes. """ - # class Luminous: - # """Luminous type of flux. - # - # By default, Luminous flux value is set to be 683 lm. - # - # Parameters - # ---------- - # luminous_flux : ansys.api.speos.source.v1.source_pb2.Luminous - # Luminous protobuf object to modify. - # default_values : bool - # Uses default values when True. - # stable_ctr : bool - # Variable to indicate if usage is inside class scope - # - # Notes - # ----- - # **Do not instantiate this class yourself**, use set_flux_luminous method available in - # Source classes. - # """ - # - # def __init__( - # self, - # luminous_flux: source_pb2.Luminous, - # default_values: bool = True, - # stable_ctr: bool = False, - # ): - # if not stable_ctr: - # msg = "Luminous class instantiated outside of class scope" - # raise RuntimeError(msg) - # self._luminous_flux = luminous_flux - # - # if default_values: - # self.value = SOURCE.LUMINOUS.VALUE - # - # @property - # def value(self) -> float: - # """Get luminous flux value. - # - # Returns - # ------- - # float - # Luminous flux value. - # """ - # return self._luminous_flux.luminous_value - # - # @value.setter - # def value(self, value: float) -> None: - # """Set luminous flux value. - # - # Parameters - # ---------- - # value: float - # Luminous flux value. - # - # Returns - # ------- - # None - # - # """ - # self._luminous_flux.luminous_value = value - # - # class Radiant: - # """Radiant type of flux. - # - # By default, Radiant flux value is set to be 1 W. - # - # Parameters - # ---------- - # radiant_flux : ansys.api.speos.source.v1.source_pb2.Radiant - # Radiant protobuf object to modify. - # default_values : bool - # Uses default values when True. - # stable_ctr : bool - # Variable to indicate if usage is inside class scope - # - # Notes - # ----- - # **Do not instantiate this class yourself**, use set_flux_radiant method available in - # Source classes. - # """ - # - # def __init__( - # self, - # radiant_flux: source_pb2.Radiant, - # default_values: bool = True, - # stable_ctr: bool = False, - # ): - # if not stable_ctr: - # msg = "Radiant class instantiated outside of class scope" - # raise RuntimeError(msg) - # self._radiant_flux = radiant_flux - # - # if default_values: - # self.value = SOURCE.RADIANT.VALUE - # - # @property - # def value(self) -> float: - # """Get radiant flux value. - # - # Returns - # ------- - # float - # Radiant flux value. - # - # """ - # return self._radiant_flux.radiant_value - # - # @value.setter - # def value(self, value: float) -> None: - # """Set radiant flux value. - # - # Parameters - # ---------- - # value: float - # Radiant flux value. - # - # Returns - # ------- - # None - # - # """ - # self._radiant_flux.radiant_value = value - def __init__( self, flux: source_pb2, @@ -750,54 +627,6 @@ def set_flux(self) -> SourceLuminaire.Flux: self._type._flux = self._source_template.luminaire return self._type - # def set_flux_luminous(self) -> SourceLuminaire.Flux.Luminous: - # """Set luminous flux. - # - # Returns - # ------- - # ansys.speos.core.source.SourceLuminaire.Luminous - # Luminaire luminous flux type source. - # """ - # if self._type is None and self._source_template.luminaire.HasField("luminous_flux"): - # self._type = SourceLuminaire.Flux.Luminous( - # luminous_flux=self._source_template.luminaire.luminous_flux, - # default_values=False, - # stable_ctr=True, - # ) - # elif not isinstance(self._type, SourceLuminaire.Flux.Luminous): - # self._type = SourceLuminaire.Flux.Luminous( - # luminous_flux=self._source_template.luminaire.luminous_flux, - # default_values=True, - # stable_ctr=True, - # ) - # elif self._type._luminous_flux is not self._source_template.luminaire.luminous_flux: - # self._type._luminous_flux = self._source_template.luminaire.luminous_flux - # return self._type - # - # def set_flux_radiant(self) -> SourceLuminaire.Flux.Radiant: - # """Set radiant flux. - # - # Returns - # ------- - # ansys.speos.core.source.SourceLuminaire.Radiant - # Luminaire radiant flux type source. - # """ - # if self._type is None and self._source_template.luminaire.HasField("radiant_flux"): - # self._type = SourceLuminaire.Flux.Radiant( - # radiant_flux=self._source_template.luminaire.radiant_flux, - # default_values=False, - # stable_ctr=True, - # ) - # elif not isinstance(self._type, SourceLuminaire.Flux.Radiant): - # self._type = SourceLuminaire.Flux.Radiant( - # radiant_flux=self._source_template.luminaire.radiant_flux, - # default_values=True, - # stable_ctr=True, - # ) - # elif self._type._radiant_flux is not self._source_template.luminaire.radiant_flux: - # self._type._radiant_flux = self._source_template.luminaire.radiant_flux - # return self._type - @property def intensity_file_uri(self) -> str: """Get intensity file. @@ -1096,54 +925,6 @@ def set_flux(self) -> SourceRayFile.Flux: self._type._flux = self._source_template.rayfile return self._type - # def set_flux_luminous(self) -> SourceRayFile.Flux.Luminous: - # """Set luminous flux. - # - # Returns - # ------- - # ansys.speos.core.source.SourceRayFile.Luminous - # Luminous flux type source. - # """ - # if self._type is None and self._source_template.rayfile.HasField("luminous_flux"): - # self._type = SourceRayFile.Flux.Luminous( - # luminous_flux=self._source_template.rayfile.luminous_flux, - # default_values=False, - # stable_ctr=True, - # ) - # elif not isinstance(self._type, SourceRayFile.Flux.Luminous): - # self._type = SourceRayFile.Flux.Luminous( - # luminous_flux=self._source_template.rayfile.luminous_flux, - # default_values=True, - # stable_ctr=True, - # ) - # elif self._type._luminous_flux is not self._source_template.rayfile.luminous_flux: - # self._type._luminous_flux = self._source_template.rayfile.luminous_flux - # return self._type - # - # def set_flux_radiant(self) -> SourceRayFile.Flux.Radiant: - # """Set radiant flux. - # - # Returns - # ------- - # ansys.speos.core.source.SourceRayFile.Radiant - # Radiant flux type source. - # """ - # if self._type is None and self._source_template.rayfile.HasField("radiant_flux"): - # self._type = SourceRayFile.Flux.Radiant( - # radiant_flux=self._source_template.rayfile.radiant_flux, - # default_values=False, - # stable_ctr=True, - # ) - # elif not isinstance(self._type, SourceRayFile.Flux.Radiant): - # self._type = SourceRayFile.Flux.Radiant( - # radiant_flux=self._source_template.rayfile.radiant_flux, - # default_values=True, - # stable_ctr=True, - # ) - # elif self._type._radiant_flux is not self._source_template.rayfile.radiant_flux: - # self._type._radiant_flux = self._source_template.rayfile.radiant_flux - # return self._type - def set_spectrum_from_ray_file(self) -> SourceRayFile: """Take spectrum from ray file provided. @@ -1260,69 +1041,6 @@ class SourceSurface(BaseSource): class Flux(BaseSource.Flux): """Different types of flux including luminous flux of intensity.""" - # - # class Intensity: - # """Intensity type of flux. - # - # By default, Intensity flux value is set to be 5 cd. - # - # Parameters - # ---------- - # intensity_flux : ansys.api.speos.source.v1.source_pb2.LuminousIntensity - # LuminousIntensity protobuf object to modify. - # default_values : bool - # Uses default values when True. - # stable_ctr : bool - # Variable to indicate if usage is inside class scope - # - # Notes - # ----- - # **Do not instantiate this class yourself**, use set_flux_luminous_intensity - # method available in Source classes. - # """ - # - # def __init__( - # self, - # intensity_flux: source_pb2.LuminousIntensity, - # default_values: bool = True, - # stable_ctr: bool = False, - # ): - # if not stable_ctr: - # msg = "Intensity class instantiated outside of class scope" - # raise RuntimeError(msg) - # self._intensity_flux = intensity_flux - # - # if default_values: - # self.value = SOURCE.INTENSITY.VALUE - # - # @property - # def value(self) -> float: - # """Get intensity flux value. - # - # Returns - # ------- - # float - # Intensity flux value. - # - # """ - # return self._intensity_flux.luminous_intensity_value - # - # @value.setter - # def value(self, value: float) -> None: - # """Set intensity flux value. - # - # Parameters - # ---------- - # value: float - # Intensity flux value. - # - # Returns - # ------- - # None - # - # """ - # self._intensity_flux.luminous_intensity_value = value - # def __init__( self, flux: source_pb2, From b7c4ad410c4b6aecedb212e318ba608a1a740c6b Mon Sep 17 00:00:00 2001 From: plu Date: Thu, 4 Sep 2025 13:56:39 +0100 Subject: [PATCH 43/52] correct example document --- examples/core/source.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/core/source.py b/examples/core/source.py index 0634c6fc6..b152656c0 100644 --- a/examples/core/source.py +++ b/examples/core/source.py @@ -115,7 +115,7 @@ def create_face(body): intensity_file_path = str(assets_data_path / IES) source2 = p.create_source(name="Luminaire.2", feature_type=SourceLuminaire) source2.intensity_file_uri = intensity_file_path -source2.set_flux_radiant().value = 1.0 # select flux radiant +source2.set_flux().set_radiant().value = 1.0 # select flux radiant # choose the source location [Origin, Xvector, Yvector, Zvector] source2.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 @@ -140,7 +140,7 @@ def create_face(body): # > changes. # > If you don't, you will still only watch what is committed on the server. -source1.set_flux_radiant().value = 1.2 # modify radiant flux value +source1.set_flux().set_radiant().value = 1.2 # modify radiant flux value source1.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 @@ -150,7 +150,7 @@ def create_face(body): # # Possibility to reset local values from the one available in the server. -source1.set_flux_luminous().value = 683.0 # modify to luminous flux BUT no commit +source1.set_flux().set_luminous().value = 683.0 # 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 @@ -184,7 +184,7 @@ def create_face(body): # - # + -source3.set_flux_luminous() +source3.set_flux().set_luminous() source3.commit() print(source3) # - @@ -207,7 +207,7 @@ def create_face(body): # - # + -source4.set_flux_luminous_intensity() +source4.set_flux().set_luminous_intensity() source4.set_intensity().set_gaussian().set_axis_system( axis_system=[10, 50, 20, 1, 0, 0, 0, 1, 0, 0, 0, 1] ) From e281307b6c27dadb1ad7059a5b692e98a401117f Mon Sep 17 00:00:00 2001 From: plu Date: Sat, 6 Sep 2025 18:21:29 +0100 Subject: [PATCH 44/52] refactor the flux properties --- src/ansys/speos/core/source.py | 50 ++++------------------------------ 1 file changed, 5 insertions(+), 45 deletions(-) diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index 73d71e9ff..6433c5f4f 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -172,7 +172,7 @@ def value(self) -> float: Returns ------- float - value of the flux. + Flux type value. """ match self._flux_type.__name__: @@ -180,6 +180,8 @@ def value(self) -> float: return self._flux_type.luminous_value case "Radiant": return self._flux_type.radiant_value + case "LuminousIntensity": + return self._flux_type.luminous_intensity_value case _: raise ValueError(f"Unsupported flux type: {self._flux_type.__name__}") @@ -202,6 +204,8 @@ def value(self, value: float) -> None: self._flux_type.luminous_value = value case "Radiant": self._flux_type.radiant_value = value + case "LuminousIntensity": + self._flux_type.luminous_intensity_value = value case _: raise ValueError(f"Unsupported flux type: {self._flux_type.__name__}") @@ -1062,50 +1066,6 @@ def set_luminous_intensity(self): """ self._flux_type = self._flux.luminous_intensity_flux - @property - def value(self) -> float: - """Get flux type's value. - - Returns - ------- - float - Flux type value. - - """ - match self._flux_type.__name__: - case "Luminous": - return self._flux_type.luminous_value - case "Radiant": - return self._flux_type.radiant_value - case "LuminousIntensity": - return self._flux_type.luminous_intensity_value - case _: - raise ValueError(f"Unsupported flux type: {self._flux_type.__name__}") - - @value.setter - def value(self, value: float) -> None: - """Set flux type's value. - - Parameters - ---------- - value: float - Value of the flux. - - Returns - ------- - None - - """ - match self._flux_type.__name__: - case "Luminous": - self._flux_type.luminous_value = value - case "Radiant": - self._flux_type.radiant_value = value - case "LuminousIntensity": - self._flux_type.luminous_intensity_value = value - case _: - raise ValueError(f"Unsupported flux type: {self._flux_type.__name__}") - class ExitanceConstant: """Type of surface source existence : existence constant. From 49979bc670f8a6215b1724044ad1c8606dcc37e4 Mon Sep 17 00:00:00 2001 From: plu Date: Sat, 6 Sep 2025 18:44:03 +0100 Subject: [PATCH 45/52] refactor the example --- examples/core/source.py | 6 ++++-- src/ansys/speos/core/source.py | 12 ++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/examples/core/source.py b/examples/core/source.py index b152656c0..da911ec0f 100644 --- a/examples/core/source.py +++ b/examples/core/source.py @@ -115,7 +115,8 @@ def create_face(body): intensity_file_path = str(assets_data_path / IES) source2 = p.create_source(name="Luminaire.2", feature_type=SourceLuminaire) source2.intensity_file_uri = intensity_file_path -source2.set_flux().set_radiant().value = 1.0 # select flux radiant +source2.set_flux().set_radiant() +source2.set_flux().value = 1.0 # select flux radiant # choose the source location [Origin, Xvector, Yvector, Zvector] source2.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 @@ -140,7 +141,8 @@ def create_face(body): # > changes. # > If you don't, you will still only watch what is committed on the server. -source1.set_flux().set_radiant().value = 1.2 # modify radiant flux value +source1.set_flux().set_radiant() +source1.set_flux().value = 1.2 # modify radiant flux value source1.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 diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index 6433c5f4f..91249ab27 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -145,25 +145,29 @@ def __init__( self.set_luminous() self.value = SOURCE.LUMINOUS.VALUE - def set_luminous(self) -> None: + def set_luminous(self) -> BaseSource.Flux: """Set flux type luminous. Returns ------- - None + ansys.speos.core.source.BaseSource.Flux + Flux object """ self._flux_type = self._flux.luminous_flux + return self - def set_radiant(self) -> None: + def set_radiant(self) -> BaseSource.Flux: """Set flux type radiant. Returns ------- - None + ansys.speos.core.source.BaseSource.Flux + Flux object """ self._flux_type = self._flux.radiant_flux + return self @property def value(self) -> float: From 8903fa04850602ea519126ad46e97ce5a299b9ee Mon Sep 17 00:00:00 2001 From: plu Date: Mon, 15 Sep 2025 14:49:36 +0100 Subject: [PATCH 46/52] constants.py default values --- src/ansys/speos/core/generic/constants.py | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/ansys/speos/core/generic/constants.py b/src/ansys/speos/core/generic/constants.py index 36ba8da67..63e964c3e 100644 --- a/src/ansys/speos/core/generic/constants.py +++ b/src/ansys/speos/core/generic/constants.py @@ -22,7 +22,9 @@ """Collection of all constants used in pySpeos.""" +from dataclasses import dataclass, field import os +from typing import Union DEFAULT_HOST: str = "localhost" """Default host used by Speos RPC server and client """ @@ -75,6 +77,30 @@ class INTENSITY: VALUE = 5 +@dataclass(frozen=True) +class FluxLuminous: + """Constant class for Luminous type Flux.""" + + value: float = 683 + + +@dataclass(frozen=True) +class FluxRadiant: + """Constant class for Radiant type Flux.""" + + value: float = 1 + + +@dataclass(frozen=True) +class SourceRayfileParamters: + """Constant class for SourceRayfileParamters.""" + + flux_from_ray_file: bool = True + flux_luminous: Union[bool, FluxLuminous] = FluxLuminous() + flux_radiant: Union[bool, FluxRadiant] = False + axis_system: list[float] = field(default_factory=lambda: [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]) + + class SENSOR: """Constant class for Sensors.""" From e522762ff6ffa6a92ad1cb212e30b36c7e1970f3 Mon Sep 17 00:00:00 2001 From: plu Date: Mon, 15 Sep 2025 15:23:26 +0100 Subject: [PATCH 47/52] refactor the constant class --- src/ansys/speos/core/generic/constants.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/ansys/speos/core/generic/constants.py b/src/ansys/speos/core/generic/constants.py index 63e964c3e..847ee4072 100644 --- a/src/ansys/speos/core/generic/constants.py +++ b/src/ansys/speos/core/generic/constants.py @@ -24,6 +24,7 @@ from dataclasses import dataclass, field import os +from pathlib import Path from typing import Union DEFAULT_HOST: str = "localhost" @@ -77,27 +78,28 @@ class INTENSITY: VALUE = 5 -@dataclass(frozen=True) +@dataclass class FluxLuminous: """Constant class for Luminous type Flux.""" value: float = 683 + flux_from_ray_file: bool = True -@dataclass(frozen=True) +@dataclass class FluxRadiant: """Constant class for Radiant type Flux.""" value: float = 1 + flux_from_ray_file: bool = True -@dataclass(frozen=True) +@dataclass class SourceRayfileParamters: """Constant class for SourceRayfileParamters.""" - flux_from_ray_file: bool = True - flux_luminous: Union[bool, FluxLuminous] = FluxLuminous() - flux_radiant: Union[bool, FluxRadiant] = False + ray_file_uri: Union[str, Path] = Path() + flux_type: Union[FluxLuminous, FluxRadiant] = FluxLuminous() axis_system: list[float] = field(default_factory=lambda: [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]) From c29c6f1db9c92d77da84d5c194983a12acfe5c9b Mon Sep 17 00:00:00 2001 From: plu Date: Mon, 15 Sep 2025 15:44:08 +0100 Subject: [PATCH 48/52] fix mutable variable --- src/ansys/speos/core/generic/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/speos/core/generic/constants.py b/src/ansys/speos/core/generic/constants.py index 847ee4072..1b6c07c4c 100644 --- a/src/ansys/speos/core/generic/constants.py +++ b/src/ansys/speos/core/generic/constants.py @@ -99,7 +99,7 @@ class SourceRayfileParamters: """Constant class for SourceRayfileParamters.""" ray_file_uri: Union[str, Path] = Path() - flux_type: Union[FluxLuminous, FluxRadiant] = FluxLuminous() + flux_type: Union[FluxLuminous, FluxRadiant] = field(default_factory=FluxLuminous) axis_system: list[float] = field(default_factory=lambda: [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]) From 06294a6b173dbf56139cd6e23449f68b8e7979ef Mon Sep 17 00:00:00 2001 From: plu Date: Tue, 16 Sep 2025 14:58:55 +0100 Subject: [PATCH 49/52] refactor the constants.py to address default parameters --- src/ansys/speos/core/generic/constants.py | 36 +++++-- src/ansys/speos/core/source.py | 110 +++++++++++++++++----- tests/core/test_source.py | 16 +++- 3 files changed, 127 insertions(+), 35 deletions(-) diff --git a/src/ansys/speos/core/generic/constants.py b/src/ansys/speos/core/generic/constants.py index 1b6c07c4c..ea3c1937f 100644 --- a/src/ansys/speos/core/generic/constants.py +++ b/src/ansys/speos/core/generic/constants.py @@ -25,7 +25,9 @@ from dataclasses import dataclass, field import os from pathlib import Path -from typing import Union +from typing import Optional, Union + +from ansys.speos.core.geo_ref import GeoRef DEFAULT_HOST: str = "localhost" """Default host used by Speos RPC server and client """ @@ -78,12 +80,23 @@ class INTENSITY: VALUE = 5 +class FluxFromFile: + """Constant class for FluxFromRayFile.""" + + pass + + +class FluxIntensity: + """Constant class for FluxIntensity.""" + + value: float = 5 + + @dataclass class FluxLuminous: """Constant class for Luminous type Flux.""" value: float = 683 - flux_from_ray_file: bool = True @dataclass @@ -91,15 +104,24 @@ class FluxRadiant: """Constant class for Radiant type Flux.""" value: float = 1 - flux_from_ray_file: bool = True @dataclass -class SourceRayfileParamters: - """Constant class for SourceRayfileParamters.""" +class SourceRayfileParameters: + """Constant class for SourceRayfileParameters.""" + + ray_file_uri: Union[str, Path] = "" + flux_type: Union[FluxLuminous, FluxRadiant, FluxFromFile] = field(default_factory=FluxFromFile) + axis_system: list[float] = field(default_factory=lambda: [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]) + exit_geometry: Optional[GeoRef] = None + + +@dataclass +class SourceLuminaireParameters: + """Constant class for SourceLuminaireParamters.""" - ray_file_uri: Union[str, Path] = Path() - flux_type: Union[FluxLuminous, FluxRadiant] = field(default_factory=FluxLuminous) + intensity_file_uri: Union[str, Path] = "" + flux_type: Union[FluxLuminous, FluxRadiant, FluxFromFile] = field(default_factory=FluxFromFile) axis_system: list[float] = field(default_factory=lambda: [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]) diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index 91249ab27..5bc6796f8 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -40,7 +40,15 @@ ) import ansys.speos.core.body as body import ansys.speos.core.face as face -from ansys.speos.core.generic.constants import ORIGIN, SOURCE +from ansys.speos.core.generic.constants import ( + ORIGIN, + SOURCE, + FluxFromFile, + FluxLuminous, + FluxRadiant, + SourceLuminaireParameters, + SourceRayfileParameters, +) import ansys.speos.core.generic.general_methods as general_methods from ansys.speos.core.generic.visualization_methods import _VisualArrow, _VisualData from ansys.speos.core.geo_ref import GeoRef @@ -132,7 +140,7 @@ class Flux: def __init__( self, flux: source_pb2, - default_values: bool = True, + default_values: Union[bool, SourceRayfileParameters], stable_ctr: bool = False, ): if not stable_ctr: @@ -141,9 +149,20 @@ def __init__( self._flux = flux self._flux_type = None - if default_values: - self.set_luminous() - self.value = SOURCE.LUMINOUS.VALUE + if isinstance(default_values, SourceRayfileParameters): + match default_values.flux_type: + case FluxLuminous(): + self.set_luminous() + self.value = default_values.flux_type.value + case FluxRadiant(): + self.set_radiant() + self.value = default_values.flux_type.value + case FluxFromFile(): + pass + case _: + raise ValueError( + f"Unsupported flux type: {type(default_values.flux_type).__name__}" + ) def set_luminous(self) -> BaseSource.Flux: """Set flux type luminous. @@ -154,7 +173,10 @@ def set_luminous(self) -> BaseSource.Flux: Flux object """ - self._flux_type = self._flux.luminous_flux + if self._flux_type is None or not isinstance( + self._flux_type, source_pb2.SourceTemplate.Luminous + ): + self._flux_type = self._flux.luminous_flux return self def set_radiant(self) -> BaseSource.Flux: @@ -166,7 +188,10 @@ def set_radiant(self) -> BaseSource.Flux: Flux object """ - self._flux_type = self._flux.radiant_flux + if self._flux_type is None or not isinstance( + self._flux_type, source_pb2.SourceTemplate.Radiant + ): + self._flux_type = self._flux.radiant_flux return self @property @@ -181,11 +206,11 @@ def value(self) -> float: """ match self._flux_type.__name__: case "Luminous": - return self._flux_type.luminous_value + return self._flux.luminous_flux.luminous_value case "Radiant": - return self._flux_type.radiant_value + return self._flux.radiant_flux.radiant_value case "LuminousIntensity": - return self._flux_type.luminous_intensity_value + return self._flux.luminous_intensity_flux.luminous_intensity_value case _: raise ValueError(f"Unsupported flux type: {self._flux_type.__name__}") @@ -205,11 +230,11 @@ def value(self, value: float) -> None: """ match self._flux_type.__name__: case "Luminous": - self._flux_type.luminous_value = value + self._flux.luminous_flux.luminous_value = value case "Radiant": - self._flux_type.radiant_value = value + self._flux.radiant_flux.radiant_value = value case "LuminousIntensity": - self._flux_type.luminous_intensity_value = value + self._flux.luminous_intensity_flux.luminous_intensity_value = value case _: raise ValueError(f"Unsupported flux type: {self._flux_type.__name__}") @@ -539,7 +564,7 @@ def __init__( description: str = "", metadata: Optional[Mapping[str, str]] = None, source_instance: Optional[ProtoScene.SourceInstance] = None, - default_values: bool = True, + default_values: SourceLuminaireParameters = SourceLuminaireParameters(), ) -> None: if metadata is None: metadata = {} @@ -562,10 +587,24 @@ def __init__( spectrum_guid=self._source_template.luminaire.spectrum_guid, ) - if default_values: + if isinstance(default_values, SourceLuminaireParameters): # Default values - self.set_flux_from_intensity_file().set_spectrum().set_incandescent() - self.axis_system = ORIGIN + self.intensity_file_uri = default_values.intensity_file_uri + self.axis_system = default_values.axis_system + match default_values.flux_type: + case FluxFromFile(): + self.set_flux_from_intensity_file() + case FluxLuminous(): + self.set_flux().set_luminous() + self.set_flux().value = default_values.flux_type.value + case FluxRadiant(): + self.set_flux().set_radiant() + self.set_flux().value = default_values.flux_type.value + case _: + raise ValueError( + f"Unsupported flux type: {type(default_values.flux_type).__name__}" + ) + self.set_spectrum().set_incandescent() @property def visual_data(self) -> _VisualData: @@ -628,7 +667,7 @@ def set_flux(self) -> SourceLuminaire.Flux: if self._type is None: self._type = self.Flux( flux=self._source_template.luminaire, - default_values=True, + default_values=SourceRayfileParameters(), stable_ctr=True, ) elif self._type._flux is not self._source_template.luminaire: @@ -747,15 +786,16 @@ class ExitGeometries: def __init__( self, rayfile_props: scene_pb2.RayFileProperties, - default_values: bool = True, + default_values: SourceRayfileParameters, stable_ctr: bool = False, ): if not stable_ctr: msg = "ExitGeometries class instantiated outside of class scope" raise RuntimeError(msg) self._rayfile_props = rayfile_props - if default_values: - self.geometries = [] + + if isinstance(default_values, SourceRayfileParameters): + self.geometries = default_values.exit_geometry @property def geometries(self) -> List[GeoRef]: @@ -800,7 +840,7 @@ def __init__( description: str = "", metadata: Optional[Mapping[str, str]] = None, source_instance: Optional[ProtoScene.SourceInstance] = None, - default_values: bool = True, + default_values: SourceRayfileParameters = SourceRayfileParameters(), ) -> None: if metadata is None: metadata = {} @@ -834,8 +874,23 @@ def __init__( if default_values: # Default values - self.set_flux_from_ray_file().set_spectrum_from_ray_file() - self.axis_system = ORIGIN + self.set_spectrum_from_ray_file() + self.ray_file_uri = default_values.ray_file_uri + match default_values.flux_type: + case FluxLuminous(): + self.set_flux().set_luminous() + self.set_flux().value = default_values.flux_type.value + case FluxRadiant(): + self.set_flux().set_radiant() + self.set_flux().value = default_values.flux_type.value + case FluxFromFile(): + self.set_flux_from_ray_file() + case _: + raise ValueError( + f"Unsupported flux type: {type(default_values.flux_type).__name__}" + ) + self.axis_system = default_values.axis_system + self.set_exit_geometries().geometries = default_values.exit_geometry @property def visual_data(self) -> _VisualData: @@ -924,12 +979,15 @@ def set_flux(self) -> SourceRayFile.Flux: """ if self._type is None: + print("case1") self._type = self.Flux( flux=self._source_template.rayfile, - default_values=True, + default_values=SourceRayfileParameters(), stable_ctr=True, ) + print(self._source_template.rayfile) elif self._type._flux is not self._source_template.rayfile: + print("case2") self._type._flux = self._source_template.rayfile return self._type @@ -1016,7 +1074,7 @@ def set_exit_geometries(self) -> SourceRayFile.ExitGeometries: elif not isinstance(self._exit_geometry_type, SourceRayFile.ExitGeometries): self._exit_geometry_type = SourceRayFile.ExitGeometries( rayfile_props=self._source_instance.rayfile_properties, - default_values=True, + default_values=SourceRayfileParameters, stable_ctr=True, ) elif ( diff --git a/tests/core/test_source.py b/tests/core/test_source.py index 56ddf9468..e05bf4f78 100644 --- a/tests/core/test_source.py +++ b/tests/core/test_source.py @@ -28,7 +28,13 @@ import pytest from ansys.speos.core import GeoRef, Project, Speos -from ansys.speos.core.generic.constants import ORIGIN, SOURCE +from ansys.speos.core.generic.constants import ( + ORIGIN, + SOURCE, + FluxLuminous, + SourceLuminaireParameters, + SourceRayfileParameters, +) from ansys.speos.core.source import ( SourceAmbientNaturalLight, SourceLuminaire, @@ -716,6 +722,9 @@ def test_luminaire_modify_after_reset(speos: Speos): # Modify after a reset # Template + assert source._source_template.luminaire.HasField("flux_from_intensity_file") + new_default_parameters = SourceLuminaireParameters(flux_type=FluxLuminous()) + source = SourceLuminaire(project=p, name="Luminaire.2", default_values=new_default_parameters) assert source.set_flux().value == 683 # assert source.set_flux_luminous().value == 683 assert source._source_template.luminaire.luminous_flux.luminous_value == 683 @@ -780,7 +789,10 @@ def test_rayfile_modify_after_reset(speos: Speos): # Modify after a reset # Template - assert source._source_template.rayfile.luminous_flux.luminous_value == 683 + assert source._source_template.rayfile.HasField("flux_from_ray_file") + new_default_parameters = SourceRayfileParameters(flux_type=FluxLuminous()) + source = SourceRayFile(project=p, name="Luminaire.2", default_values=new_default_parameters) + source.set_flux().set_luminous() source.set_flux().value = 500 # source.set_flux_luminous().value = 500 From 0b3bf199afa2efaf24b4e7c10b5161796539c08f Mon Sep 17 00:00:00 2001 From: plu Date: Thu, 18 Sep 2025 11:29:22 +0100 Subject: [PATCH 50/52] apply the constants.py discussion --- src/ansys/speos/core/generic/constants.py | 72 +++++++++++++++-------- src/ansys/speos/core/source.py | 65 ++++++++++---------- tests/core/test_source.py | 7 ++- 3 files changed, 84 insertions(+), 60 deletions(-) diff --git a/src/ansys/speos/core/generic/constants.py b/src/ansys/speos/core/generic/constants.py index ea3c1937f..2c4d8fb01 100644 --- a/src/ansys/speos/core/generic/constants.py +++ b/src/ansys/speos/core/generic/constants.py @@ -23,6 +23,7 @@ """Collection of all constants used in pySpeos.""" from dataclasses import dataclass, field +from enum import Enum import os from pathlib import Path from typing import Optional, Union @@ -80,30 +81,13 @@ class INTENSITY: VALUE = 5 -class FluxFromFile: - """Constant class for FluxFromRayFile.""" +class FluxType(Enum): + """Enum representing the type of flux.""" - pass - - -class FluxIntensity: - """Constant class for FluxIntensity.""" - - value: float = 5 - - -@dataclass -class FluxLuminous: - """Constant class for Luminous type Flux.""" - - value: float = 683 - - -@dataclass -class FluxRadiant: - """Constant class for Radiant type Flux.""" - - value: float = 1 + LUMINOUS = "luminous" + RADIANT = "radiant" + FROM_FILE = "from_file" + INTENSITY = "intensity" @dataclass @@ -111,19 +95,57 @@ class SourceRayfileParameters: """Constant class for SourceRayfileParameters.""" ray_file_uri: Union[str, Path] = "" - flux_type: Union[FluxLuminous, FluxRadiant, FluxFromFile] = field(default_factory=FluxFromFile) + flux_type: FluxType = FluxType.FROM_FILE + flux_value: Optional[float] = None axis_system: list[float] = field(default_factory=lambda: [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]) exit_geometry: Optional[GeoRef] = None + def __post_init__(self): + """Verify the dataclass initiation.""" + # Validation: restrict flux_type + if self.flux_type not in {FluxType.FROM_FILE, FluxType.LUMINOUS, FluxType.RADIANT}: + raise ValueError( + f"Invalid flux_type '{self.flux_type}'. Must be FROM_FILE, LUMINOUS, or RADIANT." + ) + + # Set default flux_value based on flux_type (only if not manually provided) + if self.flux_value is None: + match self.flux_type: + case FluxType.LUMINOUS: + self.flux_value = 683 + case FluxType.RADIANT: + self.flux_value = 1 + case FluxType.FROM_FILE: + self.flux_value = 0.0 + @dataclass class SourceLuminaireParameters: """Constant class for SourceLuminaireParamters.""" intensity_file_uri: Union[str, Path] = "" - flux_type: Union[FluxLuminous, FluxRadiant, FluxFromFile] = field(default_factory=FluxFromFile) + flux_type: FluxType = FluxType.FROM_FILE + flux_value: Optional[float] = None axis_system: list[float] = field(default_factory=lambda: [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]) + def __post_init__(self) -> None: + """Verify the dataclass initiation.""" + # Validation: restrict flux_type + if self.flux_type not in {FluxType.FROM_FILE, FluxType.LUMINOUS, FluxType.RADIANT}: + raise ValueError( + f"Invalid flux_type '{self.flux_type}'. Must be FROM_FILE, LUMINOUS, or RADIANT." + ) + + # Set default flux_value based on flux_type (only if not manually provided) + if self.flux_value is None: + match self.flux_type: + case FluxType.LUMINOUS: + self.flux_value = 683 + case FluxType.RADIANT: + self.flux_value = 1 + case FluxType.FROM_FILE: + self.flux_value = 0.0 + class SENSOR: """Constant class for Sensors.""" diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index 5bc6796f8..dd136b69d 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -43,9 +43,7 @@ from ansys.speos.core.generic.constants import ( ORIGIN, SOURCE, - FluxFromFile, - FluxLuminous, - FluxRadiant, + FluxType, SourceLuminaireParameters, SourceRayfileParameters, ) @@ -140,7 +138,7 @@ class Flux: def __init__( self, flux: source_pb2, - default_values: Union[bool, SourceRayfileParameters], + default_values: Union[bool, SourceRayfileParameters, SourceLuminaireParameters], stable_ctr: bool = False, ): if not stable_ctr: @@ -149,15 +147,15 @@ def __init__( self._flux = flux self._flux_type = None - if isinstance(default_values, SourceRayfileParameters): + if isinstance(default_values, (SourceRayfileParameters, SourceLuminaireParameters)): match default_values.flux_type: - case FluxLuminous(): + case FluxType.LUMINOUS: self.set_luminous() - self.value = default_values.flux_type.value - case FluxRadiant(): + self.value = default_values.flux_value + case FluxType.RADIANT: self.set_radiant() - self.value = default_values.flux_type.value - case FluxFromFile(): + self.value = default_values.flux_value + case FluxType.FROM_FILE: pass case _: raise ValueError( @@ -564,7 +562,7 @@ def __init__( description: str = "", metadata: Optional[Mapping[str, str]] = None, source_instance: Optional[ProtoScene.SourceInstance] = None, - default_values: SourceLuminaireParameters = SourceLuminaireParameters(), + default_values: Optional[bool, SourceLuminaireParameters] = None, ) -> None: if metadata is None: metadata = {} @@ -587,19 +585,21 @@ def __init__( spectrum_guid=self._source_template.luminaire.spectrum_guid, ) - if isinstance(default_values, SourceLuminaireParameters): - # Default values + if default_values is not False: + if not isinstance(default_values, SourceLuminaireParameters): + default_values = SourceLuminaireParameters() # customized default values + # New Default values self.intensity_file_uri = default_values.intensity_file_uri self.axis_system = default_values.axis_system match default_values.flux_type: - case FluxFromFile(): + case FluxType.FROM_FILE: self.set_flux_from_intensity_file() - case FluxLuminous(): + case FluxType.LUMINOUS: self.set_flux().set_luminous() - self.set_flux().value = default_values.flux_type.value - case FluxRadiant(): + self.set_flux().value = default_values.flux_value + case FluxType.RADIANT: self.set_flux().set_radiant() - self.set_flux().value = default_values.flux_type.value + self.set_flux().value = default_values.flux_value case _: raise ValueError( f"Unsupported flux type: {type(default_values.flux_type).__name__}" @@ -786,7 +786,7 @@ class ExitGeometries: def __init__( self, rayfile_props: scene_pb2.RayFileProperties, - default_values: SourceRayfileParameters, + default_values: Optional[bool, SourceRayfileParameters], stable_ctr: bool = False, ): if not stable_ctr: @@ -794,7 +794,9 @@ def __init__( raise RuntimeError(msg) self._rayfile_props = rayfile_props - if isinstance(default_values, SourceRayfileParameters): + if default_values is not False: + if not isinstance(default_values, SourceRayfileParameters): + default_values = SourceRayfileParameters() self.geometries = default_values.exit_geometry @property @@ -840,7 +842,7 @@ def __init__( description: str = "", metadata: Optional[Mapping[str, str]] = None, source_instance: Optional[ProtoScene.SourceInstance] = None, - default_values: SourceRayfileParameters = SourceRayfileParameters(), + default_values: Optional[bool, SourceRayfileParameters] = None, ) -> None: if metadata is None: metadata = {} @@ -872,18 +874,20 @@ def __init__( # Attribute gathering more complex exit geometries settings self._exit_geometry_type = None - if default_values: - # Default values + if default_values is not False: # True, SourceRayfileParameters as default + if not isinstance(default_values, SourceRayfileParameters): # True as default + default_values = SourceRayfileParameters() + # Default values self.set_spectrum_from_ray_file() self.ray_file_uri = default_values.ray_file_uri match default_values.flux_type: - case FluxLuminous(): + case FluxType.LUMINOUS: self.set_flux().set_luminous() - self.set_flux().value = default_values.flux_type.value - case FluxRadiant(): + self.set_flux().value = default_values.flux_value + case FluxType.RADIANT: self.set_flux().set_radiant() - self.set_flux().value = default_values.flux_type.value - case FluxFromFile(): + self.set_flux().value = default_values.flux_value + case FluxType.FROM_FILE: self.set_flux_from_ray_file() case _: raise ValueError( @@ -979,15 +983,12 @@ def set_flux(self) -> SourceRayFile.Flux: """ if self._type is None: - print("case1") self._type = self.Flux( flux=self._source_template.rayfile, default_values=SourceRayfileParameters(), stable_ctr=True, ) - print(self._source_template.rayfile) elif self._type._flux is not self._source_template.rayfile: - print("case2") self._type._flux = self._source_template.rayfile return self._type @@ -1074,7 +1075,7 @@ def set_exit_geometries(self) -> SourceRayFile.ExitGeometries: elif not isinstance(self._exit_geometry_type, SourceRayFile.ExitGeometries): self._exit_geometry_type = SourceRayFile.ExitGeometries( rayfile_props=self._source_instance.rayfile_properties, - default_values=SourceRayfileParameters, + default_values=SourceRayfileParameters(), stable_ctr=True, ) elif ( diff --git a/tests/core/test_source.py b/tests/core/test_source.py index e05bf4f78..e89186462 100644 --- a/tests/core/test_source.py +++ b/tests/core/test_source.py @@ -31,7 +31,7 @@ from ansys.speos.core.generic.constants import ( ORIGIN, SOURCE, - FluxLuminous, + FluxType, SourceLuminaireParameters, SourceRayfileParameters, ) @@ -723,7 +723,7 @@ def test_luminaire_modify_after_reset(speos: Speos): # Modify after a reset # Template assert source._source_template.luminaire.HasField("flux_from_intensity_file") - new_default_parameters = SourceLuminaireParameters(flux_type=FluxLuminous()) + new_default_parameters = SourceLuminaireParameters(flux_type=FluxType.LUMINOUS) source = SourceLuminaire(project=p, name="Luminaire.2", default_values=new_default_parameters) assert source.set_flux().value == 683 # assert source.set_flux_luminous().value == 683 @@ -790,8 +790,9 @@ def test_rayfile_modify_after_reset(speos: Speos): # Modify after a reset # Template assert source._source_template.rayfile.HasField("flux_from_ray_file") - new_default_parameters = SourceRayfileParameters(flux_type=FluxLuminous()) + new_default_parameters = SourceRayfileParameters(flux_type=FluxType.LUMINOUS) source = SourceRayFile(project=p, name="Luminaire.2", default_values=new_default_parameters) + assert source.set_flux().value == 683 source.set_flux().set_luminous() source.set_flux().value = 500 From d99d8b18686533af519ed304c9dc6159d97c294b Mon Sep 17 00:00:00 2001 From: plu Date: Tue, 23 Sep 2025 12:09:14 +0100 Subject: [PATCH 51/52] change to constants.py ORIGIN --- src/ansys/speos/core/generic/constants.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ansys/speos/core/generic/constants.py b/src/ansys/speos/core/generic/constants.py index 2c4d8fb01..568504322 100644 --- a/src/ansys/speos/core/generic/constants.py +++ b/src/ansys/speos/core/generic/constants.py @@ -97,7 +97,7 @@ class SourceRayfileParameters: ray_file_uri: Union[str, Path] = "" flux_type: FluxType = FluxType.FROM_FILE flux_value: Optional[float] = None - axis_system: list[float] = field(default_factory=lambda: [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]) + axis_system: list[float] = field(default_factory=lambda: ORIGIN) exit_geometry: Optional[GeoRef] = None def __post_init__(self): @@ -126,7 +126,7 @@ class SourceLuminaireParameters: intensity_file_uri: Union[str, Path] = "" flux_type: FluxType = FluxType.FROM_FILE flux_value: Optional[float] = None - axis_system: list[float] = field(default_factory=lambda: [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]) + axis_system: list[float] = field(default_factory=lambda: ORIGIN) def __post_init__(self) -> None: """Verify the dataclass initiation.""" From 823781c2a1f75f2763a08589f17d1f819954d1a7 Mon Sep 17 00:00:00 2001 From: plu Date: Tue, 23 Sep 2025 12:27:20 +0100 Subject: [PATCH 52/52] add comparison with value from default parameter instance --- tests/core/test_source.py | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/tests/core/test_source.py b/tests/core/test_source.py index e89186462..be6977610 100644 --- a/tests/core/test_source.py +++ b/tests/core/test_source.py @@ -50,15 +50,21 @@ def test_create_luminaire_source(speos: Speos): # Default value # source1 = p.create_source(name="Luminaire.1") + default_parameter = SourceLuminaireParameters() source1 = SourceLuminaire(p, "Luminaire.1") assert source1._source_template.HasField("luminaire") - assert source1._source_template.luminaire.intensity_file_uri == "" + assert ( + source1._source_template.luminaire.intensity_file_uri + == default_parameter.intensity_file_uri + ) assert source1._source_template.luminaire.HasField("flux_from_intensity_file") assert source1._spectrum._spectrum._spectrum.HasField("predefined") assert source1._spectrum._spectrum._spectrum.predefined.HasField("incandescent") assert source1._spectrum._spectrum._spectrum.name == "Luminaire.1.Spectrum" assert source1._source_instance.HasField("luminaire_properties") - assert source1._source_instance.luminaire_properties.axis_system == ORIGIN + assert ( + source1._source_instance.luminaire_properties.axis_system == default_parameter.axis_system + ) # intensity_file_uri source1.intensity_file_uri = Path(test_path) / "IES_C_DETECTOR.ies" @@ -319,12 +325,13 @@ def test_create_rayfile_source(speos: Speos): p, name="Ray-file.1", ) + default_parameter = SourceRayfileParameters() assert source1._source_instance.HasField("rayfile_properties") - assert source1._source_instance.rayfile_properties.axis_system == ORIGIN + assert source1._source_instance.rayfile_properties.axis_system == default_parameter.axis_system assert source1._source_template.HasField("rayfile") assert source1._source_template.rayfile.HasField("flux_from_ray_file") assert source1._source_template.rayfile.HasField("spectrum_from_ray_file") - assert source1._source_template.rayfile.ray_file_uri == "" + assert source1._source_template.rayfile.ray_file_uri == default_parameter.ray_file_uri # ray_file_uri source1.ray_file_uri = Path(test_path) / "Rays.ray" @@ -725,9 +732,17 @@ def test_luminaire_modify_after_reset(speos: Speos): assert source._source_template.luminaire.HasField("flux_from_intensity_file") new_default_parameters = SourceLuminaireParameters(flux_type=FluxType.LUMINOUS) source = SourceLuminaire(project=p, name="Luminaire.2", default_values=new_default_parameters) - assert source.set_flux().value == 683 - # assert source.set_flux_luminous().value == 683 - assert source._source_template.luminaire.luminous_flux.luminous_value == 683 + assert source.set_flux().value == new_default_parameters.flux_value + assert source.axis_system == new_default_parameters.axis_system + assert ( + source._source_template.luminaire.luminous_flux.luminous_value + == new_default_parameters.flux_value + ) + assert ( + source._source_instance.luminaire_properties.axis_system + == new_default_parameters.axis_system + ) + source.set_flux().set_luminous() source.set_flux().value = 500 # source.set_flux_luminous().value = 500 @@ -792,7 +807,15 @@ def test_rayfile_modify_after_reset(speos: Speos): assert source._source_template.rayfile.HasField("flux_from_ray_file") new_default_parameters = SourceRayfileParameters(flux_type=FluxType.LUMINOUS) source = SourceRayFile(project=p, name="Luminaire.2", default_values=new_default_parameters) - assert source.set_flux().value == 683 + assert source.axis_system == new_default_parameters.axis_system + assert source.set_flux().value == new_default_parameters.flux_value + assert ( + source._source_instance.rayfile_properties.axis_system == new_default_parameters.axis_system + ) + assert ( + source._source_template.rayfile.luminous_flux.luminous_value + == new_default_parameters.flux_value + ) source.set_flux().set_luminous() source.set_flux().value = 500