diff --git a/ansys/fluent/core/meta.py b/ansys/fluent/core/meta.py index 52ab3215720c..2229e6eb075f 100644 --- a/ansys/fluent/core/meta.py +++ b/ansys/fluent/core/meta.py @@ -9,13 +9,86 @@ class LocalObjectDataExtractor: + """Class to extract data for local objects.""" + + class _SurfaceAPI: + """Class providing APIs for surface operations.""" + + def __init__(self, obj): + self.obj = obj + self._surface_name_on_server = self.surface_name_in_server( + obj._name + ) + + @staticmethod + def surface_name_in_server(local_surface_name): + return "_dummy_surface_for_pyfluent:" + local_surface_name + + def _get_api_handle(self): + return self.obj._get_top_most_parent().session.tui.solver.surface + + def _delete_if_exist_on_server(self): + field_info = self.obj._data_extractor.field_info() + surfaces_list = list(field_info.get_surfaces_info().keys()) + if self._surface_name_on_server in surfaces_list: + self.delete_surface_on_server() + + def create_surface_on_server(self): + if self.obj.surface.type() == "iso-surface": + iso_surface = self.obj.surface.iso_surface + field = iso_surface.field() + iso_value = iso_surface.iso_value() + if not field: + raise RuntimeError("Iso surface definition is incomplete.") + self._delete_if_exist_on_server() + self._get_api_handle().iso_surface( + field, self._surface_name_on_server, (), (), iso_value, () + ) + elif self.obj.surface.type() == "plane-surface": + plane_surface = self.obj.surface.plane_surface + xy_plane = plane_surface.xy_plane + yz_plane = plane_surface.yz_plane + zx_plane = plane_surface.zx_plane + self._delete_if_exist_on_server() + self._get_api_handle().plane_surface( + self._surface_name_on_server, + "xy-plane" + if xy_plane + else "yz-plane" + if yz_plane + else "zx-plane", + xy_plane.z() + if xy_plane + else yz_plane.x() + if yz_plane + else zx_plane.y(), + ) + field_info = self.obj._data_extractor.field_info() + surfaces_list = list(field_info.get_surfaces_info().keys()) + if self._surface_name_on_server not in surfaces_list: + raise RuntimeError("Surface creation failed.") + + def delete_surface_on_server(self): + self._get_api_handle().delete_surface(self._surface_name_on_server) + def __init__(self, obj): + self.obj = obj self.field_info = lambda: obj._get_top_most_parent().session.field_info self.field_data = lambda: obj._get_top_most_parent().session.field_data - self.surface_api = ( - lambda: obj._get_top_most_parent().session.tui.solver.surface - ) self.id = lambda: obj._get_top_most_parent().session.id + if obj.__class__.__name__ == "Surface": + self.surface_api = LocalObjectDataExtractor._SurfaceAPI(obj) + + def remote_surface_name(self, local_surface_name): + local_surfaces_provider = ( + self.obj._get_top_most_parent()._local_surfaces_provider() + ) + if local_surface_name in list(local_surfaces_provider): + return LocalObjectDataExtractor._SurfaceAPI.surface_name_in_server( + local_surface_name + ) + else: + return local_surface_name class Attribute: diff --git a/ansys/fluent/post/matplotlib/matplot_windows_manager.py b/ansys/fluent/post/matplotlib/matplot_windows_manager.py index 89725c8b138a..ae979177131b 100644 --- a/ansys/fluent/post/matplotlib/matplot_windows_manager.py +++ b/ansys/fluent/post/matplotlib/matplot_windows_manager.py @@ -130,7 +130,9 @@ def _get_xy_plot_data(self): surfaces_info = field_info.get_surfaces_info() surface_ids = [ id - for surf in obj.surfaces_list() + for surf in map( + obj._data_extractor.remote_surface_name, obj.surfaces_list() + ) for id in surfaces_info[surf]["surface_id"] ] # get scalar field data diff --git a/ansys/fluent/post/post_object_defns.py b/ansys/fluent/post/post_object_defns.py index 306a5b81629b..1d0a71e92974 100644 --- a/ansys/fluent/post/post_object_defns.py +++ b/ansys/fluent/post/post_object_defns.py @@ -20,16 +20,8 @@ def _pre_display(self): for surf_name in self.surfaces_list(): if surf_name in list(local_surfaces_provider): surf_obj = local_surfaces_provider[surf_name] - if surf_obj.surface.type() == "iso-surface": - surf_api = surf_obj._data_extractor.surface_api() - surf_api.iso_surface( - surf_obj.surface.iso_surface.field(), - surf_name, - (), - (), - surf_obj.surface.iso_surface.iso_value(), - (), - ) + surf_api = surf_obj._data_extractor.surface_api + surf_api.create_surface_on_server() def _post_display(self): local_surfaces_provider = ( @@ -38,8 +30,8 @@ def _post_display(self): for surf_name in self.surfaces_list(): if surf_name in list(local_surfaces_provider): surf_obj = local_surfaces_provider[surf_name] - surf_api = surf_obj._data_extractor.surface_api() - surf_api.delete_surface(surf_name) + surf_api = surf_obj._data_extractor.surface_api + surf_api.delete_surface_on_server() class GraphicsDefn( @@ -196,6 +188,70 @@ def allowed_values(self): class plane_surface(metaclass=PyLocalObjectMeta): """Plane surface data.""" + def _availability(self, name): + if name == "xy_plane": + return self.creation_method() == "xy-plane" + if name == "yz_plane": + return self.creation_method() == "yz-plane" + if name == "zx_plane": + return self.creation_method() == "zx-plane" + return True + + class creation_method(metaclass=PyLocalPropertyMeta): + """Creation Method.""" + + value: str = "xy-plane" + + @Attribute + def allowed_values(self): + """Surface type allowed values.""" + return ["xy-plane", "yz-plane", "zx-plane"] + + class xy_plane(metaclass=PyLocalObjectMeta): + """XY Plane.""" + + class z(metaclass=PyLocalPropertyMeta): + """Z value.""" + + value: float = 0 + + @Attribute + def range(self): + """Z value range.""" + return self._data_extractor.field_info().get_range( + "z-coordinate", True + ) + + class yz_plane(metaclass=PyLocalObjectMeta): + """YZ Plane.""" + + class x(metaclass=PyLocalPropertyMeta): + """X value.""" + + value: float = 0 + + @Attribute + def range(self): + """X value range.""" + return self._data_extractor.field_info().get_range( + "x-coordinate", True + ) + + class zx_plane(metaclass=PyLocalObjectMeta): + """ZX Plane.""" + + class y(metaclass=PyLocalPropertyMeta): + """Y value.""" + + value: float = 0 + + @Attribute + def range(self): + """Y value range.""" + return self._data_extractor.field_info().get_range( + "y-coordinate", True + ) + class iso_surface(metaclass=PyLocalObjectMeta): """Iso surface data.""" @@ -292,7 +348,24 @@ class filled(metaclass=PyLocalPropertyMeta): class node_values(metaclass=PyLocalPropertyMeta): """Show nodal data.""" - value: bool = True + _value: bool = True + + @property + def value(self): + """Node value property setter.""" + filled = self._get_parent_by_type(ContourDefn).filled() + auto_range_off = self._get_parent_by_type( + ContourDefn + ).range.auto_range_off + if not filled or ( + auto_range_off and auto_range_off.clip_to_range() + ): + self._value = True + return self._value + + @value.setter + def value(self, value): + self._value = value class boundary_values(metaclass=PyLocalPropertyMeta): """Show boundary values.""" diff --git a/ansys/fluent/post/pyvista/pyvista_windows_manager.py b/ansys/fluent/post/pyvista/pyvista_windows_manager.py index 90a12637b1f3..ca4d196eadc2 100644 --- a/ansys/fluent/post/pyvista/pyvista_windows_manager.py +++ b/ansys/fluent/post/pyvista/pyvista_windows_manager.py @@ -55,8 +55,7 @@ def plot(self): if obj.__class__.__name__ == "Mesh": self._display_mesh(obj, plotter) elif obj.__class__.__name__ == "Surface": - if obj.surface.type() == "iso-surface": - self._display_iso_surface(obj, plotter) + self._display_surface(obj, plotter) elif obj.__class__.__name__ == "Contour": self._display_contour(obj, plotter) elif obj.__class__.__name__ == "Vector": @@ -101,7 +100,9 @@ def _display_vector( surfaces_info = field_info.get_surfaces_info() surface_ids = [ id - for surf in obj.surfaces_list() + for surf in map( + obj._data_extractor.remote_surface_name, obj.surfaces_list() + ) for id in surfaces_info[surf]["surface_id"] ] @@ -189,7 +190,9 @@ def _display_contour( surfaces_info = field_info.get_surfaces_info() surface_ids = [ id - for surf in obj.surfaces_list() + for surf in map( + obj._data_extractor.remote_surface_name, obj.surfaces_list() + ) for id in surfaces_info[surf]["surface_id"] ] # get scalar field data @@ -294,45 +297,31 @@ def _display_contour( ): plotter.add_mesh(mesh.contour(isosurfaces=20)) - def _display_iso_surface( + def _display_surface( self, obj, plotter: Union[BackgroundPlotter, pv.Plotter] ): - field = obj.surface.iso_surface.field() - if not field: - raise RuntimeError("Iso surface definition is incomplete.") - - dummy_surface_name = "_dummy_iso_surface_for_pyfluent" - field_info = obj._data_extractor.field_info() - surfaces_list = list(field_info.get_surfaces_info().keys()) - iso_value = obj.surface.iso_surface.iso_value() - if dummy_surface_name in surfaces_list: - obj._data_extractor.surface_api().delete_surface( - dummy_surface_name - ) - - obj._data_extractor.surface_api().iso_surface( - field, dummy_surface_name, (), (), iso_value, () - ) - - surfaces_list = list(field_info.get_surfaces_info().keys()) - if dummy_surface_name not in surfaces_list: - raise RuntimeError("Iso surface creation failed.") + surface_api = obj._data_extractor.surface_api + surface_api.create_surface_on_server() + dummy_object = "dummy_object" post_session = obj._get_top_most_parent() - if obj.surface.iso_surface.rendering() == "mesh": - mesh = post_session.Meshes[dummy_surface_name] - mesh.surfaces_list = [dummy_surface_name] - mesh.show_edges = True - self._display_mesh(mesh, plotter) - del post_session.Meshes[dummy_surface_name] - else: - contour = post_session.Contours[dummy_surface_name] + if ( + obj.surface.type() == "iso-surface" + and obj.surface.iso_surface.rendering() == "contour" + ): + contour = post_session.Contours[dummy_object] contour.field = obj.surface.iso_surface.field() - contour.surfaces_list = [dummy_surface_name] + contour.surfaces_list = [obj._name] contour.show_edges = True contour.range.auto_range_on.global_range = True self._display_contour(contour, plotter) - del post_session.Contours[dummy_surface_name] - obj._data_extractor.surface_api().delete_surface(dummy_surface_name) + del post_session.Contours[dummy_object] + else: + mesh = post_session.Meshes[dummy_object] + mesh.surfaces_list = [obj._name] + mesh.show_edges = True + self._display_mesh(mesh, plotter) + del post_session.Meshes[dummy_object] + surface_api.delete_surface_on_server() def _display_mesh( self, obj, plotter: Union[BackgroundPlotter, pv.Plotter] @@ -344,7 +333,9 @@ def _display_mesh( surfaces_info = field_info.get_surfaces_info() surface_ids = [ id - for surf in obj.surfaces_list() + for surf in map( + obj._data_extractor.remote_surface_name, obj.surfaces_list() + ) for id in surfaces_info[surf]["surface_id"] ] surfaces_data = field_data.get_surfaces(surface_ids) diff --git a/tests/test_post.py b/tests/test_post.py index 7beb8bab0a1b..e4792848464a 100644 --- a/tests/test_post.py +++ b/tests/test_post.py @@ -152,17 +152,23 @@ def test_contour_object(): contour1 = pyvista_graphics.Contours["contour-1"] field_info = contour1._data_extractor.field_info() + # Surfaces allowed values should be all surfaces. assert contour1.surfaces_list.allowed_values == list( field_info.get_surfaces_info().keys() ) + # Invalid surface should raise exception. with pytest.raises(ValueError) as value_error: contour1.surfaces_list = "surface_does_not_exist" + # Invalid surface should raise exception. with pytest.raises(ValueError) as value_error: contour1.surfaces_list = ["surface_does_not_exist"] + + # Should accept all valid surface. contour1.surfaces_list = contour1.surfaces_list.allowed_values + # Field allowed values should be all fields. assert contour1.field.allowed_values == [ v["solver_name"] for k, v in field_info.get_fields_info().items() ] @@ -170,19 +176,40 @@ def test_contour_object(): # Important. Because there is no type checking so following passes. contour1.field = [contour1.field.allowed_values[0]] + # Should accept all valid fields. contour1.field = contour1.field.allowed_values[0] + + # Invalid field should raise exception. with pytest.raises(ValueError) as value_error: contour1.field = "field_does_not_exist" # Important. Because there is no type checking so following passes. contour1.node_values = "value should be boolean" + # changing filled to False or setting clip_to_range should set node_value + # to True. + contour1.node_values = False + assert contour1.node_values() == False + contour1.filled = False + assert contour1.node_values() == True + # node value can not be set to False because Filled is False + contour1.node_values = False + assert contour1.node_values() == True + + contour1.filled = True + contour1.node_values = False + assert contour1.node_values() == False + contour1.range.option = "auto-range-off" + contour1.range.auto_range_off.clip_to_range = True + assert contour1.node_values() == True + contour1.range.option = "auto-range-on" assert contour1.range.auto_range_off is None contour1.range.option = "auto-range-off" assert contour1.range.auto_range_on is None + # Range should adjust to min/max of node field values. contour1.node_values = True contour1.field = "temperature" surfaces_id = [ @@ -197,6 +224,7 @@ def test_contour_object(): assert range[0] == pytest.approx(contour1.range.auto_range_off.minimum()) assert range[1] == pytest.approx(contour1.range.auto_range_off.maximum()) + # Range should adjust to min/max of cell field values. contour1.node_values = False range = field_info.get_range( contour1.field(), contour1.node_values(), surfaces_id @@ -204,6 +232,7 @@ def test_contour_object(): assert range[0] == pytest.approx(contour1.range.auto_range_off.minimum()) assert range[1] == pytest.approx(contour1.range.auto_range_off.maximum()) + # Range should adjust to min/max of node field values contour1.field = "pressure" range = field_info.get_range( contour1.field(), contour1.node_values(), surfaces_id @@ -257,6 +286,15 @@ def test_surface_object(): surf1 = pyvista_graphics.Surfaces["surf-1"] field_info = surf1._data_extractor.field_info() + surf1.surface.type = "iso-surface" + assert surf1.surface.plane_surface is None + surf1.surface.type = "plane-surface" + assert surf1.surface.iso_surface is None + + surf1.surface.plane_surface.creation_method = "xy-plane" + assert surf1.surface.plane_surface.yz_plane is None + assert surf1.surface.plane_surface.zx_plane is None + surf1.surface.type = "iso-surface" iso_surf = surf1.surface.iso_surface