diff --git a/doc/changelog.d/690.added.md b/doc/changelog.d/690.added.md new file mode 100644 index 000000000..ca7be60e0 --- /dev/null +++ b/doc/changelog.d/690.added.md @@ -0,0 +1 @@ +Refactor source class 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() ``` 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 diff --git a/examples/core/project.py b/examples/core/project.py index 4575b887c..139233de3 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() 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 e30e77aca..da911ec0f 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,11 @@ 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.set_flux().set_radiant() +source2.set_flux().value = 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 +141,9 @@ 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.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 print(source1) @@ -150,7 +152,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.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 @@ -178,13 +180,13 @@ 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) # - # + -source3.set_flux_luminous() +source3.set_flux().set_luminous() source3.commit() print(source3) # - @@ -198,18 +200,16 @@ 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) # - # + -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] ) 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() # - diff --git a/src/ansys/speos/core/generic/constants.py b/src/ansys/speos/core/generic/constants.py index 19ab3d01c..568504322 100644 --- a/src/ansys/speos/core/generic/constants.py +++ b/src/ansys/speos/core/generic/constants.py @@ -22,7 +22,13 @@ """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 + +from ansys.speos.core.geo_ref import GeoRef DEFAULT_HOST: str = "localhost" """Default host used by Speos RPC server and client """ @@ -38,3 +44,142 @@ """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.""" + + class MONOCHROMATIC: + """Constant class for Monochromatic.""" + + WAVELENGTH = 555 + + 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 INTENSITY: + """Constant class for Intensity.""" + + VALUE = 5 + + +class FluxType(Enum): + """Enum representing the type of flux.""" + + LUMINOUS = "luminous" + RADIANT = "radiant" + FROM_FILE = "from_file" + INTENSITY = "intensity" + + +@dataclass +class SourceRayfileParameters: + """Constant class for 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: ORIGIN) + 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: FluxType = FluxType.FROM_FILE + flux_value: Optional[float] = None + axis_system: list[float] = field(default_factory=lambda: ORIGIN) + + 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.""" + + 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..9df5bbbb9 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, @@ -712,9 +781,27 @@ def __init__( if default_values: # Default values - self.set_sampling() + self.sampling = SENSOR.LAYERTYPES.INCIDENCE_SAMPLING + + @property + def sampling(self) -> BaseSensor.LayerTypeIncidenceAngle: + """Set the sampling for incidence angles. + + Parameters + ---------- + value : int + Sampling for incidence angles. + By default, ``9``. - def set_sampling(self, value: int = 9) -> BaseSensor.LayerTypeIncidenceAngle: + 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 = {} diff --git a/src/ansys/speos/core/source.py b/src/ansys/speos/core/source.py index 583765fc6..dd136b69d 100644 --- a/src/ansys/speos/core/source.py +++ b/src/ansys/speos/core/source.py @@ -26,21 +26,31 @@ import datetime from difflib import SequenceMatcher +from pathlib import Path from typing import List, Mapping, Optional, Union import uuid 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 ( + ORIGIN, + SOURCE, + FluxType, + 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 +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 @@ -106,6 +116,126 @@ def __init__( self.source_template_link = self._project.client[source_instance.source_guid] self._reset() + class Flux: + """Type of flux. + + By default, Luminous flux value is set with value 683 lm. + + 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 + + Notes + ----- + **Do not instantiate this class yourself**, use set_flux method available in source classes. + """ + + def __init__( + self, + flux: source_pb2, + default_values: Union[bool, SourceRayfileParameters, SourceLuminaireParameters], + 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 + + if isinstance(default_values, (SourceRayfileParameters, SourceLuminaireParameters)): + match default_values.flux_type: + case FluxType.LUMINOUS: + self.set_luminous() + self.value = default_values.flux_value + case FluxType.RADIANT: + self.set_radiant() + self.value = default_values.flux_value + case FluxType.FROM_FILE: + pass + case _: + raise ValueError( + f"Unsupported flux type: {type(default_values.flux_type).__name__}" + ) + + def set_luminous(self) -> BaseSource.Flux: + """Set flux type luminous. + + Returns + ------- + ansys.speos.core.source.BaseSource.Flux + Flux object + + """ + 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: + """Set flux type radiant. + + Returns + ------- + ansys.speos.core.source.BaseSource.Flux + Flux object + + """ + 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 + def value(self) -> float: + """Get flux type's value. + + Returns + ------- + float + Flux type value. + + """ + match self._flux_type.__name__: + case "Luminous": + return self._flux.luminous_flux.luminous_value + case "Radiant": + return self._flux.radiant_flux.radiant_value + case "LuminousIntensity": + return self._flux.luminous_intensity_flux.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.luminous_flux.luminous_value = value + case "Radiant": + self._flux.radiant_flux.radiant_value = value + case "LuminousIntensity": + self._flux.luminous_intensity_flux.luminous_intensity_value = value + case _: + raise ValueError(f"Unsupported flux type: {self._flux_type.__name__}") + class _Spectrum: def __init__( self, @@ -432,7 +562,7 @@ def __init__( description: str = "", metadata: Optional[Mapping[str, str]] = None, source_instance: Optional[ProtoScene.SourceInstance] = None, - default_values: bool = True, + default_values: Optional[bool, SourceLuminaireParameters] = None, ) -> None: if metadata is None: metadata = {} @@ -445,6 +575,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, @@ -452,10 +585,26 @@ def __init__( spectrum_guid=self._source_template.luminaire.spectrum_guid, ) - if default_values: - # Default values - self.set_flux_from_intensity_file().set_spectrum().set_incandescent() - self.set_axis_system() + 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 FluxType.FROM_FILE: + self.set_flux_from_intensity_file() + case FluxType.LUMINOUS: + self.set_flux().set_luminous() + self.set_flux().value = default_values.flux_value + case FluxType.RADIANT: + self.set_flux().set_radiant() + self.set_flux().value = default_values.flux_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: @@ -506,55 +655,50 @@ 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: - """Set luminous flux. - - Parameters - ---------- - value : float - Luminous flux in lumens. - By default, ``683.0``. + def set_flux(self) -> SourceLuminaire.Flux: + """Set flux of the luminaire source. Returns ------- - ansys.speos.core.source.SourceLuminaire - Luminaire source. - """ - self._source_template.luminaire.luminous_flux.luminous_value = value - return self + ansys.speos.core.source.SourceLuminaire.Flux + flux object of the source - def set_flux_radiant(self, value: float = 1) -> SourceLuminaire: - """Set radiant flux. + """ + if self._type is None: + self._type = self.Flux( + flux=self._source_template.luminaire, + default_values=SourceRayfileParameters(), + stable_ctr=True, + ) + elif self._type._flux is not self._source_template.luminaire: + self._type._flux = self._source_template.luminaire + return self._type - Parameters - ---------- - value : float - Radiant flux in watts. - By default, ``1.0``. + @property + def intensity_file_uri(self) -> str: + """Get intensity file. Returns ------- - ansys.speos.core.source.SourceLuminaire - Luminaire source. + str + Intensity file uri. """ - self._source_template.luminaire.radiant_flux.radiant_value = value - return self + return self._source_template.luminaire.intensity_file_uri - def set_intensity_file_uri(self, uri: str) -> SourceLuminaire: + @intensity_file_uri.setter + def intensity_file_uri(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,24 +713,33 @@ 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[float]: + """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[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]``. 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): @@ -610,6 +763,77 @@ 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: Optional[bool, 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 is not False: + if not isinstance(default_values, SourceRayfileParameters): + default_values = SourceRayfileParameters() + self.geometries = default_values.exit_geometry + + @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, @@ -618,7 +842,7 @@ def __init__( description: str = "", metadata: Optional[Mapping[str, str]] = None, source_instance: Optional[ProtoScene.SourceInstance] = None, - default_values: bool = True, + default_values: Optional[bool, SourceRayfileParameters] = None, ) -> None: if metadata is None: metadata = {} @@ -645,11 +869,32 @@ def __init__( self.set_spectrum_from_ray_file() 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 - self.set_flux_from_ray_file().set_spectrum_from_ray_file() - self.set_axis_system() + 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 FluxType.LUMINOUS: + self.set_flux().set_luminous() + self.set_flux().value = default_values.flux_value + case FluxType.RADIANT: + self.set_flux().set_radiant() + self.set_flux().value = default_values.flux_value + case FluxType.FROM_FILE: + 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: @@ -689,21 +934,33 @@ 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_flux_from_ray_file(self) -> SourceRayFile: """Take flux from ray file provided. @@ -716,39 +973,24 @@ 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: - """Set luminous flux. - - Parameters - ---------- - value : float - Luminous flux in lumens. - By default, ``683.0``. + def set_flux(self) -> SourceRayFile.Flux: + """Set flux of the Rayfile source. Returns ------- - ansys.speos.core.source.SourceRayFile - RayFile source. - """ - self._source_template.rayfile.luminous_flux.luminous_value = value - return self - - def set_flux_radiant(self, value: float = 1) -> SourceRayFile: - """Set radiant flux. - - Parameters - ---------- - value : float - Radiant flux in watts. - By default, ``1.0``. + ansys.speos.core.source.SourceRayFile.Flux + flux object of the source - Returns - ------- - ansys.speos.core.source.SourceRayFile - RayFile source. """ - self._source_template.rayfile.radiant_flux.radiant_value = value - return self + if self._type is None: + self._type = self.Flux( + flux=self._source_template.rayfile, + default_values=SourceRayfileParameters(), + stable_ctr=True, + ) + elif self._type._flux is not self._source_template.rayfile: + self._type._flux = self._source_template.rayfile + return self._type def set_spectrum_from_ray_file(self) -> SourceRayFile: """Take spectrum from ray file provided. @@ -783,47 +1025,64 @@ 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_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=SourceRayfileParameters(), + 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): @@ -846,6 +1105,113 @@ class SourceSurface(BaseSource): Uses default values when True. """ + class Flux(BaseSource.Flux): + """Different types of flux including luminous flux of intensity.""" + + 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 set_luminous_intensity(self): + """Set flux type luminous intensity. + + Returns + ------- + None + + """ + self._flux_type = self._flux.luminous_intensity_flux + + 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. @@ -884,44 +1250,65 @@ def __init__( if default_values: # Default values self._exitance_variable.SetInParent() - self.set_axis_plane() + self.axis_plane = ORIGIN[0:9] - def set_xmp_file_uri(self, uri: str) -> SourceSurface.ExitanceVariable: - """Set existence xmp file. + @property + def xmp_file_uri(self) -> str: + """Get xmp file uri. + + Returns + ------- + str + xmp file uri. + + """ + 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) - def set_axis_plane( - self, axis_plane: Optional[List[float]] = None - ) -> SourceSurface.ExitanceVariable: - """Set position of the existence map. + @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 + + @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__( @@ -965,10 +1352,16 @@ 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().set_luminous() + self.set_flux().value = SOURCE.LUMINOUS.VALUE + # self.set_flux_luminous() + self.set_exitance_constant().geometries = [] + self.set_intensity() self.set_spectrum() @property @@ -987,7 +1380,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 @@ -1024,58 +1419,26 @@ 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: - """Set luminous flux. - - Parameters - ---------- - value : float - Luminous flux in lumens. - By default, ``683.0``. - - Returns - ------- - ansys.speos.core.source.SourceSurface - Surface source. - """ - self._source_template.surface.luminous_flux.luminous_value = value - return self - - def set_flux_radiant(self, value: float = 1) -> SourceSurface: - """Set radiant flux. - - Parameters - ---------- - value : float - Radiant flux in watts. - By default, ``1.0``. + def set_flux(self) -> SourceSurface.Flux: + """Set flux of the Surface source. Returns ------- - ansys.speos.core.source.SourceSurface - Surface 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. - - Parameters - ---------- - value : float - Luminous intensity in candelas. - By default, ``5.0``. + ansys.speos.core.source.SourceSurface.Flux + flux object of the source - Returns - ------- - ansys.speos.core.source.SourceSurface - Surface source. """ - self._source_template.surface.luminous_intensity_flux.luminous_intensity_value = value - return self + 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._flux is not self._source_template.surface: + self._flux_type._flux = self._source_template.surface + return self._flux_type - def set_intensity(self) -> Intensity: + def set_intensity(self) -> intensity.Intensity: """Set intensity. Returns @@ -1094,49 +1457,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. diff --git a/src/ansys/speos/core/spectrum.py b/src/ansys/speos/core/spectrum.py index e508f4799..9172eb5bc 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 = "Monochromatic 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 = "Blackbody 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 = "Sampled 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,79 @@ 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 + + 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 def set_library(self, file_uri: str) -> Spectrum: """Set the spectrum as library. diff --git a/tests/core/test_project.py b/tests/core/test_project.py index 7104b3109..f0bf12f7d 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 @@ -360,7 +360,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() @@ -477,7 +477,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() @@ -485,13 +485,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() @@ -505,13 +505,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 fafd5fc4f..5b8d1b05a 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 @@ -271,7 +271,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 @@ -300,7 +300,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 @@ -333,7 +333,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..71199379b 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 @@ -485,10 +485,13 @@ 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() + 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 @@ -511,9 +514,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 +563,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 +668,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,8 +692,9 @@ 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 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 @@ -800,9 +806,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,10 +841,19 @@ 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.commit() + 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.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 @@ -923,10 +938,10 @@ 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 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 ( @@ -1053,7 +1068,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 +1174,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 +1271,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 +1316,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 +1349,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 +1394,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 +1436,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 diff --git a/tests/core/test_simulation.py b/tests/core/test_simulation.py index e8122a744..f99f27d42 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,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().set_x_sampling(10).set_y_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) @@ -1047,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]: @@ -1085,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) @@ -1102,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() @@ -1124,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 3a679b110..be6977610 100644 --- a/tests/core/test_source.py +++ b/tests/core/test_source.py @@ -25,7 +25,16 @@ import datetime from pathlib import Path +import pytest + from ansys.speos.core import GeoRef, Project, Speos +from ansys.speos.core.generic.constants import ( + ORIGIN, + SOURCE, + FluxType, + SourceLuminaireParameters, + SourceRayfileParameters, +) from ansys.speos.core.source import ( SourceAmbientNaturalLight, SourceLuminaire, @@ -41,32 +50,26 @@ 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 == [ - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 1, - ] + assert ( + source1._source_instance.luminaire_properties.axis_system == default_parameter.axis_system + ) # 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.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 != "" @@ -78,14 +81,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().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().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 @@ -95,8 +106,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, @@ -129,6 +142,13 @@ def test_create_luminaire_source(speos: Speos): 1, ] + 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, + ) + source1.delete() assert len(p.scene_link.get().sources) == 0 @@ -150,14 +170,16 @@ 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") 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" @@ -182,20 +204,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().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 @@ -203,31 +235,25 @@ 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() + 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") 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 - 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 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, @@ -242,13 +268,13 @@ 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 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" @@ -256,10 +282,37 @@ 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 + 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, + ) + + 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() @@ -272,29 +325,18 @@ 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 == [ - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 1, - ] + 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.set_ray_file_uri(uri=str(Path(test_path) / "Rays.ray")) + 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 != "" @@ -302,14 +344,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().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().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 @@ -319,7 +369,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 != "" @@ -329,8 +380,9 @@ 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.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, @@ -348,13 +400,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 == [ @@ -362,10 +413,19 @@ 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 + 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() @@ -542,7 +602,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 @@ -559,7 +619,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 @@ -570,9 +630,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 @@ -592,7 +654,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 @@ -604,7 +666,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() @@ -616,7 +678,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") @@ -624,10 +687,13 @@ 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_exit_geometries( - exit_geometries=[GeoRef.from_native_link("TheBodyB/TheFaceB1")] - ) # instance + 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 + 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 == [] @@ -653,9 +719,9 @@ 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().set_luminous() + # source.set_flux_luminous() source.commit() # Ask for reset @@ -663,8 +729,23 @@ def test_luminaire_modify_after_reset(speos: Speos): # Modify after a reset # Template - assert source._source_template.luminaire.luminous_flux.luminous_value == 683 - source.set_flux_luminous(value=500) + 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 == 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 assert source._source_template.luminaire.luminous_flux.luminous_value == 500 # Intermediate class for spectrum @@ -687,7 +768,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, @@ -712,9 +793,10 @@ 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.set_flux().set_luminous() + source.ray_file_uri = Path(test_path) / "RaysWithoutSpectralData.RAY" + source.set_spectrum() source.commit() # Ask for reset @@ -722,8 +804,22 @@ 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) + 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.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 + # source.set_flux_luminous().value = 500 assert source._source_template.rayfile.luminous_flux.luminous_value == 500 # Intermediate class for spectrum @@ -746,7 +842,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, @@ -770,10 +866,12 @@ 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_flux().set_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() @@ -783,7 +881,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 @@ -808,7 +908,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, @@ -829,9 +929,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 @@ -866,7 +966,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 @@ -885,7 +985,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 @@ -902,7 +1003,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 diff --git a/tests/core/test_spectrum.py b/tests/core/test_spectrum.py index 1659b7faf..05ebafdd9 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 @@ -37,17 +39,25 @@ 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.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).commit() + 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 # 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.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] @@ -59,34 +69,63 @@ 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") + with pytest.raises(RuntimeError, match="Blackbody class instantiated outside of class scope"): + Spectrum.Blackbody( + blackbody=spectrum1._spectrum.blackbody, + default_values=True, + stable_ctr=False, + ) + + with pytest.raises( + RuntimeError, match="Monochromatic class instantiated outside of class scope" + ): + Spectrum.Monochromatic( + monochromatic=spectrum1._spectrum.monochromatic, + default_values=True, + stable_ctr=False, + ) + + with pytest.raises(RuntimeError, match="Sampled class instantiated outside of class scope"): + Spectrum.Sampled( + sampled=spectrum1._spectrum.sampled, + default_values=True, + stable_ctr=False, + ) spectrum1.delete() @@ -94,7 +133,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 +148,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 +169,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")