diff --git a/doc/source/conf.py b/doc/source/conf.py index 4417532f..428c7ab9 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -60,9 +60,9 @@ intersphinx_mapping = { "python": ("https://docs.python.org/dev", None), "scipy": ("https://docs.scipy.org/doc/scipy/reference", None), - "numpy": ("https://numpy.org/devdocs", None), + "numpy": ("https://numpy.org/doc/stable/", None), "matplotlib": ("https://matplotlib.org/stable", None), - "pandas": ("https://pandas.pydata.org/pandas-docs/stable", None), + "pandas": ("https://pandas.pydata.org/docs/", None), "pyvista": ("https://docs.pyvista.org/", None), } diff --git a/pyproject.toml b/pyproject.toml index 3c3371c6..0416d39b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,10 +31,11 @@ vtk = [ { url = "https://github.com/pyvista/pyvista-wheels/raw/main/vtk-9.1.0.dev0-cp310-cp310-win_amd64.whl" , markers = "python_version > '3.9' and sys_platform != 'linux'"}, { version = "9.1.0", python = "<=3.9" }, ] -pyvista = "0.33.2" -pyvistaqt = "0.7.0" -pyside6 = "6.2.3" -matplotlib = "3.5.1" +ipyvtklink = ">=0.2.2" +pyvista = ">=0.33.2" +pyvistaqt = ">=0.7.0" +pyside6 = ">=6.2.3" +matplotlib = ">=3.5.1" [tool.black] line-length = 88 diff --git a/src/ansys/fluent/visualization/matplotlib/matplot_objects.py b/src/ansys/fluent/visualization/matplotlib/matplot_objects.py index 98a82c52..3bd67a34 100644 --- a/src/ansys/fluent/visualization/matplotlib/matplot_objects.py +++ b/src/ansys/fluent/visualization/matplotlib/matplot_objects.py @@ -39,6 +39,8 @@ def __init__(self, session, local_surfaces_provider=None): ) def _init_module(self, obj, mod): + from ansys.fluent.visualization.post_helper import PostAPIHelper + for name, cls in mod.__dict__.items(): if cls.__class__.__name__ in ( @@ -47,7 +49,7 @@ def _init_module(self, obj, mod): setattr( obj, cls.PLURAL, - PyLocalContainer(self, cls), + PyLocalContainer(self, cls, PostAPIHelper), ) diff --git a/src/ansys/fluent/visualization/matplotlib/matplot_windows_manager.py b/src/ansys/fluent/visualization/matplotlib/matplot_windows_manager.py index 57baa773..a609a8cc 100644 --- a/src/ansys/fluent/visualization/matplotlib/matplot_windows_manager.py +++ b/src/ansys/fluent/visualization/matplotlib/matplot_windows_manager.py @@ -128,13 +128,13 @@ def __call__(self): """Draw XY plot.""" if not self.post_object: return + xy_data = XYPlotDataExtractor(self.post_object).fetch_data() properties = { - "curves": self.post_object.surfaces_list(), + "curves": list(xy_data), "title": "XY Plot", "xlabel": "position", "ylabel": self.post_object.y_axis_function(), } - xy_data = XYPlotDataExtractor(self.post_object).fetch_data() if in_notebook() or get_config()["blocking"]: self.plotter.set_properties(properties) else: @@ -170,7 +170,7 @@ def __call__(self): """Draw Monitor plot.""" if not self.post_object: return - monitors_manager = self.post_object._data_extractor.monitors_manager() + monitors_manager = self.post_object._api_helper.monitors_manager() indices, columns_data = monitors_manager.get_monitor_set_data( self.post_object.monitor_set_name() ) @@ -405,8 +405,7 @@ def _get_windows_id( for window_id, window in self._post_windows.items() if not window.plotter.is_closed() and ( - not session_id - or session_id == window.post_object._data_extractor.id() + not session_id or session_id == window.post_object._api_helper.id() ) ] if not windows_id or window_id in windows_id diff --git a/src/ansys/fluent/visualization/post_data_extractor.py b/src/ansys/fluent/visualization/post_data_extractor.py index cc38f27a..fc0a43f8 100644 --- a/src/ansys/fluent/visualization/post_data_extractor.py +++ b/src/ansys/fluent/visualization/post_data_extractor.py @@ -1,5 +1,6 @@ """Module providing data extractor APIs.""" +import itertools from typing import Dict from ansys.api.fluent.v0.field_data_pb2 import PayloadTag @@ -46,14 +47,12 @@ def _fetch_mesh_data(self, obj, *args, **kwargs): if not obj.surfaces_list(): raise RuntimeError("Mesh definition is incomplete.") obj._pre_display() - field_info = obj._data_extractor.field_info() - field_data = obj._data_extractor.field_data() + field_info = obj._api_helper.field_info() + field_data = obj._api_helper.field_data() surfaces_info = field_info.get_surfaces_info() surface_ids = [ id - for surf in map( - obj._data_extractor.remote_surface_name, obj.surfaces_list() - ) + for surf in map(obj._api_helper.remote_surface_name, obj.surfaces_list()) for id in surfaces_info[surf]["surface_id"] ] @@ -64,7 +63,7 @@ def _fetch_mesh_data(self, obj, *args, **kwargs): return surfaces_data def _fetch_surface_data(self, obj, *args, **kwargs): - surface_api = obj._data_extractor.surface_api + surface_api = obj._api_helper.surface_api surface_api.create_surface_on_server() dummy_object = "dummy_object" post_session = obj._get_top_most_parent() @@ -100,14 +99,12 @@ def _fetch_contour_data(self, obj, *args, **kwargs): node_values = obj.node_values() boundary_values = obj.boundary_values() - field_info = obj._data_extractor.field_info() - field_data = obj._data_extractor.field_data() + field_info = obj._api_helper.field_info() + field_data = obj._api_helper.field_data() surfaces_info = field_info.get_surfaces_info() surface_ids = [ id - for surf in map( - obj._data_extractor.remote_surface_name, obj.surfaces_list() - ) + for surf in map(obj._api_helper.remote_surface_name, obj.surfaces_list()) for id in surfaces_info[surf]["surface_id"] ] # get scalar field data @@ -144,16 +141,14 @@ def _fetch_vector_data(self, obj, *args, **kwargs): raise RuntimeError("Vector definition is incomplete.") obj._pre_display() - field_info = obj._data_extractor.field_info() - field_data = obj._data_extractor.field_data() + field_info = obj._api_helper.field_info() + field_data = obj._api_helper.field_data() # surface ids surfaces_info = field_info.get_surfaces_info() surface_ids = [ id - for surf in map( - obj._data_extractor.remote_surface_name, obj.surfaces_list() - ) + for surf in map(obj._api_helper.remote_surface_name, obj.surfaces_list()) for id in surfaces_info[surf]["surface_id"] ] @@ -210,16 +205,36 @@ def _fetch_xy_data(self, obj): boundary_values = obj.boundary_values() direction_vector = obj.direction_vector() surfaces_list = obj.surfaces_list() - field_info = obj._data_extractor.field_info() - field_data = obj._data_extractor.field_data() + field_info = obj._api_helper.field_info() + field_data = obj._api_helper.field_data() surfaces_info = field_info.get_surfaces_info() surface_ids = [ id - for surf in map( - obj._data_extractor.remote_surface_name, obj.surfaces_list() - ) + for surf in map(obj._api_helper.remote_surface_name, obj.surfaces_list()) for id in surfaces_info[surf]["surface_id"] ] + # For group surfaces, expanded surf name is used. + # If group1 consists of id 3,4,5 then corresponding surface name will be + # group:3, group:4, group:5 + surfaces_list_expanded = [ + expanded_surf_name + for expanded_surf_name_list in itertools.starmap( + lambda local_surface_name, id_list: [local_surface_name] + if len(id_list) == 1 + else [f"{local_surface_name}:{id}" for id in id_list], + [ + ( + local_surface_name, + surfaces_info[remote_surface_name]["surface_id"], + ) + for remote_surface_name, local_surface_name in zip( + map(obj._api_helper.remote_surface_name, surfaces_list), + surfaces_list, + ) + ], + ) + for expanded_surf_name in expanded_surf_name_list + ] # get scalar field data field_data.add_get_surfaces_request( @@ -248,18 +263,22 @@ def _fetch_xy_data(self, obj): surface_tag = 0 xyplot_payload_data = field_data.get_fields() data_tag = location_tag | boundary_value_tag + if data_tag not in xyplot_payload_data: + raise RuntimeError("Plot surface is not valid.") xyplot_data = xyplot_payload_data[data_tag] surface_data = xyplot_payload_data[surface_tag] # loop over all surfaces xy_plots_data = {} - surfaces_list_iter = iter(surfaces_list) + surfaces_list_iter = iter(surfaces_list_expanded) for surface_id, mesh_data in surface_data.items(): mesh_data["vertices" if node_values else "centroid"].shape = ( mesh_data["vertices" if node_values else "centroid"].size // 3, 3, ) y_values = xyplot_data[surface_id][field] + if y_values is None: + continue x_values = np.matmul( mesh_data["vertices" if node_values else "centroid"], direction_vector, diff --git a/src/ansys/fluent/visualization/post_helper.py b/src/ansys/fluent/visualization/post_helper.py new file mode 100644 index 00000000..e1f0df79 --- /dev/null +++ b/src/ansys/fluent/visualization/post_helper.py @@ -0,0 +1,142 @@ +import re + + +class PostAPIHelper: + """Class providing helper API for post 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.lower() + + def _get_api_handle(self): + return self.obj._get_top_most_parent().session.solver.tui.surface + + def _delete_if_exist_on_server(self): + field_info = self.obj._api_helper.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() + phases = self.obj._api_helper._get_phases() + unit_quantity = self.obj._api_helper._field_unit_quantity(field) + unit_info = self.obj._api_helper._fluent_unit_info(unit_quantity) + if phases: + phases = list(filter(field.startswith, phases)) + if phases: + domain, field = ( + field[0 : len(phases[0])], + field[len(phases[0]) + 1 :], + ) + else: + domain = "mixture" + self._get_api_handle().iso_surface( + domain, + field, + self._surface_name_on_server, + (), + (), + (iso_value / unit_info[1]) - unit_info[2], + (), + ) + else: + self._get_api_handle().iso_surface( + field, + self._surface_name_on_server, + (), + (), + (iso_value / unit_info[1]) - unit_info[2], + (), + ) + 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() + unit_info = self.obj._api_helper._fluent_unit_info("length") + 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() / unit_info[1]) - unit_info[2] + if xy_plane + else (yz_plane.x() / unit_info[1]) - unit_info[2] + if yz_plane + else (zx_plane.y() / unit_info[1]) - unit_info[2], + ) + field_info = self.obj._api_helper.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.monitors_manager = ( + lambda: obj._get_top_most_parent().session.monitors_manager + ) + self.id = lambda: obj._get_top_most_parent().session.id + if obj.__class__.__name__ == "Surface": + self.surface_api = PostAPIHelper._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 PostAPIHelper._SurfaceAPI.surface_name_in_server(local_surface_name) + else: + return local_surface_name + + # Following functions will be deprecated in future. + def get_vector_fields(self): + scheme_eval_str = "(map car (apply append (map client-inquire-cell-vector-functions (inquire-domain-for-cell-functions))))" # noqa: E501 + return self._scheme_str_to_py_list(scheme_eval_str) + + def _get_phases(self): + scheme_eval_str = "(map domain-name (get-phase-domains))" + return self._scheme_str_to_py_list(scheme_eval_str) + + def _field_unit_quantity(self, field): + scheme_eval_str = f"(cdr (assq 'units (%fill-render-info '{field})))" + return self._scheme_str_to_py_list(scheme_eval_str)[0] + + def _fluent_unit_info(self, unit_quantity): + def to_float(number): + try: + return float(number) + except ValueError: + return number + + scheme_eval_str = ( + f"(units/inquire-label-scale-offset-for-quantity '{unit_quantity})" + ) + unit_info = [ + to_float(data) for data in self._scheme_str_to_py_list(scheme_eval_str) + ] + if len(unit_info) == 2: + unit_info.insert(0, "") + return unit_info + + def _scheme_str_to_py_list(self, scheme_eval_str): + session = self.obj._get_top_most_parent().session + str = session.scheme_eval.string_eval(scheme_eval_str) + return list(filter(None, re.split(r'[\s()"\']', str))) diff --git a/src/ansys/fluent/visualization/post_object_defns.py b/src/ansys/fluent/visualization/post_object_defns.py index a9a8cd67..2a3864bb 100644 --- a/src/ansys/fluent/visualization/post_object_defns.py +++ b/src/ansys/fluent/visualization/post_object_defns.py @@ -18,7 +18,7 @@ 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] - surf_api = surf_obj._data_extractor.surface_api + surf_api = surf_obj._api_helper.surface_api surf_api.create_surface_on_server() def _post_display(self): @@ -26,7 +26,7 @@ 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 = surf_obj._api_helper.surface_api surf_api.delete_surface_on_server() @@ -81,7 +81,7 @@ class monitor_set_name(metaclass=PyLocalPropertyMeta): @Attribute def allowed_values(self): """Monitor set allowed values.""" - return self._data_extractor.monitors_manager().get_monitor_set_names() + return self._api_helper.monitors_manager().get_monitor_set_names() class XYPlotDefn(PlotDefn): @@ -112,10 +112,7 @@ class y_axis_function(metaclass=PyLocalPropertyMeta): @Attribute def allowed_values(self): """Y axis function allowed values.""" - return [ - v["solver_name"] - for k, v in self._data_extractor.field_info().get_fields_info().items() - ] + return list(self._api_helper.field_info().get_fields_info()) class x_axis_function(metaclass=PyLocalPropertyMeta): """X Axis Function.""" @@ -136,7 +133,7 @@ class surfaces_list(metaclass=PyLocalPropertyMeta): def allowed_values(self): """Surface list allowed values.""" return list( - self._data_extractor.field_info().get_surfaces_info().keys() + self._api_helper.field_info().get_surfaces_info().keys() ) + list(self._get_top_most_parent()._local_surfaces_provider()) @@ -154,7 +151,7 @@ class surfaces_list(metaclass=PyLocalPropertyMeta): def allowed_values(self): """Surface list allowed values.""" return list( - (self._data_extractor.field_info().get_surfaces_info().keys()) + (self._api_helper.field_info().get_surfaces_info().keys()) ) + list(self._get_top_most_parent()._local_surfaces_provider()) class show_edges(metaclass=PyLocalPropertyMeta): @@ -226,7 +223,7 @@ class z(metaclass=PyLocalPropertyMeta): @Attribute def range(self): """Z value range.""" - return self._data_extractor.field_info().get_range( + return self._api_helper.field_info().get_range( "z-coordinate", True ) @@ -241,7 +238,7 @@ class x(metaclass=PyLocalPropertyMeta): @Attribute def range(self): """X value range.""" - return self._data_extractor.field_info().get_range( + return self._api_helper.field_info().get_range( "x-coordinate", True ) @@ -256,7 +253,7 @@ class y(metaclass=PyLocalPropertyMeta): @Attribute def range(self): """Y value range.""" - return self._data_extractor.field_info().get_range( + return self._api_helper.field_info().get_range( "y-coordinate", True ) @@ -271,11 +268,7 @@ class field(metaclass=PyLocalPropertyMeta): @Attribute def allowed_values(self): """Field allowed values.""" - field_info = self._data_extractor.field_info() - return [ - v["solver_name"] - for k, v in field_info.get_fields_info().items() - ] + return list(self._api_helper.field_info().get_fields_info()) class rendering(metaclass=PyLocalPropertyMeta): """Iso surface rendering.""" @@ -312,7 +305,7 @@ def range(self): """Iso value range.""" field = self._parent.field() if field: - return self._data_extractor.field_info().get_range(field, True) + return self._api_helper.field_info().get_range(field, True) class ContourDefn(GraphicsDefn): @@ -328,8 +321,7 @@ class field(metaclass=PyLocalPropertyMeta): @Attribute def allowed_values(self): """Field allowed values.""" - field_info = self._data_extractor.field_info() - return [v["solver_name"] for k, v in field_info.get_fields_info().items()] + return list(self._api_helper.field_info().get_fields_info()) class surfaces_list(metaclass=PyLocalPropertyMeta): """Contour surfaces.""" @@ -340,7 +332,7 @@ class surfaces_list(metaclass=PyLocalPropertyMeta): def allowed_values(self): """Surfaces list allowed values.""" return list( - self._data_extractor.field_info().get_surfaces_info().keys() + self._api_helper.field_info().get_surfaces_info().keys() ) + list(self._get_top_most_parent()._local_surfaces_provider()) class filled(metaclass=PyLocalPropertyMeta): @@ -434,7 +426,7 @@ def value(self): if getattr(self, "_value", None) is None: field = self._get_parent_by_type(ContourDefn).field() if field: - field_info = self._data_extractor.field_info() + field_info = self._api_helper.field_info() field_range = field_info.get_range( field, self._get_parent_by_type(ContourDefn).node_values(), @@ -463,7 +455,7 @@ def value(self): if getattr(self, "_value", None) is None: field = self._get_parent_by_type(ContourDefn).field() if field: - field_info = self._data_extractor.field_info() + field_info = self._api_helper.field_info() field_range = field_info.get_range( field, self._get_parent_by_type(ContourDefn).node_values(), @@ -490,9 +482,7 @@ class vectors_of(metaclass=PyLocalPropertyMeta): @Attribute def allowed_values(self): """Vectors of allowed values.""" - return list( - self._data_extractor.field_info().get_vector_fields_info().keys() - ) + return list(self._api_helper.get_vector_fields()) class surfaces_list(metaclass=PyLocalPropertyMeta): """List of surfaces for vector graphics.""" @@ -503,7 +493,7 @@ class surfaces_list(metaclass=PyLocalPropertyMeta): def allowed_values(self): """Surface list allowed values.""" return list( - self._data_extractor.field_info().get_surfaces_info().keys() + self._api_helper.field_info().get_surfaces_info().keys() ) + list(self._get_top_most_parent()._local_surfaces_provider()) class scale(metaclass=PyLocalPropertyMeta): @@ -566,7 +556,7 @@ class minimum(metaclass=PyLocalPropertyMeta): def value(self): """Range minimum property setter.""" if getattr(self, "_value", None) is None: - field_info = self._data_extractor.field_info() + field_info = self._api_helper.field_info() field_range = field_info.get_range( "velocity-magnitude", False, @@ -587,7 +577,7 @@ class maximum(metaclass=PyLocalPropertyMeta): def value(self): """Range maximum property setter.""" if getattr(self, "_value", None) is None: - field_info = self._data_extractor.field_info() + field_info = self._api_helper.field_info() field_range = field_info.get_range( "velocity-magnitude", False, diff --git a/src/ansys/fluent/visualization/pyvista/pyvista_objects.py b/src/ansys/fluent/visualization/pyvista/pyvista_objects.py index a91ee75d..c52ea7bf 100644 --- a/src/ansys/fluent/visualization/pyvista/pyvista_objects.py +++ b/src/ansys/fluent/visualization/pyvista/pyvista_objects.py @@ -45,6 +45,8 @@ def __init__(self, session, local_surfaces_provider=None): ) def _init_module(self, obj, mod): + from ansys.fluent.visualization.post_helper import PostAPIHelper + for name, cls in mod.__dict__.items(): if cls.__class__.__name__ in ( @@ -53,7 +55,7 @@ def _init_module(self, obj, mod): setattr( obj, cls.PLURAL, - PyLocalContainer(self, cls), + PyLocalContainer(self, cls, PostAPIHelper), ) def add_outline_mesh(self): @@ -73,7 +75,7 @@ def add_outline_mesh(self): outline_mesh = meshes[outline_mesh_id] outline_mesh.surfaces_list = [ k - for k, v in outline_mesh._data_extractor.field_info() + for k, v in outline_mesh._api_helper.field_info() .get_surfaces_info() .items() if v["type"] == "zone-surf" and v["zone_type"] != "interior" diff --git a/src/ansys/fluent/visualization/pyvista/pyvista_windows_manager.py b/src/ansys/fluent/visualization/pyvista/pyvista_windows_manager.py index 85e96783..d5bba084 100644 --- a/src/ansys/fluent/visualization/pyvista/pyvista_windows_manager.py +++ b/src/ansys/fluent/visualization/pyvista/pyvista_windows_manager.py @@ -106,15 +106,13 @@ def _scalar_bar_default_properties(self) -> dict: def _display_vector(self, obj, plotter: Union[BackgroundPlotter, pv.Plotter]): vector_field_data = FieldDataExtractor(obj).fetch_data() - field_info = obj._data_extractor.field_info() + field_info = obj._api_helper.field_info() # surface ids surfaces_info = field_info.get_surfaces_info() surface_ids = [ id - for surf in map( - obj._data_extractor.remote_surface_name, obj.surfaces_list() - ) + for surf in map(obj._api_helper.remote_surface_name, obj.surfaces_list()) for id in surfaces_info[surf]["surface_id"] ] @@ -125,6 +123,8 @@ def _display_vector(self, obj, plotter: Union[BackgroundPlotter, pv.Plotter]): field = "velocity-magnitude" for surface_id, mesh_data in vector_field_data.items(): + if "vertices" not in mesh_data or "faces" not in mesh_data: + continue mesh_data["vertices"].shape = mesh_data["vertices"].size // 3, 3 mesh_data[obj.vectors_of()].shape = ( mesh_data[obj.vectors_of()].size // 3, @@ -194,6 +194,8 @@ def _display_contour(self, obj, plotter: Union[BackgroundPlotter, pv.Plotter]): # loop over all meshes for surface_id, surface_data in scalar_field_data.items(): + if "vertices" not in surface_data or "faces" not in surface_data: + continue surface_data["vertices"].shape = surface_data["vertices"].size // 3, 3 topology = "line" if surface_data["faces"][0] == 2 else "face" if topology == "line": @@ -257,7 +259,7 @@ def _display_contour(self, obj, plotter: Union[BackgroundPlotter, pv.Plotter]): auto_range_on = obj.range.auto_range_on if auto_range_on.global_range(): if filled: - field_info = obj._data_extractor.field_info() + field_info = obj._api_helper.field_info() plotter.add_mesh( mesh, clim=field_info.get_range(field, False), @@ -284,7 +286,7 @@ def _display_contour(self, obj, plotter: Union[BackgroundPlotter, pv.Plotter]): plotter.add_mesh(mesh.contour(isosurfaces=20)) def _display_surface(self, obj, plotter: Union[BackgroundPlotter, pv.Plotter]): - surface_api = obj._data_extractor.surface_api + surface_api = obj._api_helper.surface_api surface_api.create_surface_on_server() dummy_object = "dummy_object" post_session = obj._get_top_most_parent() @@ -311,6 +313,8 @@ def _display_mesh(self, obj, plotter: Union[BackgroundPlotter, pv.Plotter]): surfaces_data = FieldDataExtractor(obj).fetch_data() for surface_id, mesh_data in surfaces_data.items(): + if "vertices" not in mesh_data or "faces" not in mesh_data: + continue mesh_data["vertices"].shape = mesh_data["vertices"].size // 3, 3 topology = "line" if mesh_data["faces"][0] == 2 else "face" if topology == "line": @@ -634,7 +638,7 @@ def _get_windows_id( if not window.plotter._closed and ( not session_id - or session_id == window.post_object._data_extractor.id() + or session_id == window.post_object._api_helper.id() ) ] if not windows_id or window_id in windows_id diff --git a/tests/session.dump b/tests/session.dump index 27eb2543..49d7fd88 100644 Binary files a/tests/session.dump and b/tests/session.dump differ diff --git a/tests/test_post.py b/tests/test_post.py index d6d5dcb9..2c87cbcf 100644 --- a/tests/test_post.py +++ b/tests/test_post.py @@ -11,10 +11,10 @@ @pytest.fixture(autouse=True) -def patch_mock_data_extractor(mocker) -> None: +def patch_mock_api_helper(mocker) -> None: mocker.patch( - "ansys.fluent.core.meta.LocalObjectDataExtractor", - MockLocalObjectDataExtractor, + "ansys.fluent.visualization.post_helper.PostAPIHelper", + MockAPIHelper, ) @@ -155,22 +155,20 @@ def get_surfaces_info(self) -> dict: return self._session_data["surfaces_info"] -class MockLocalObjectDataExtractor: +class MockAPIHelper: _session_data = None _session_dump = "tests//session.dump" def __init__(self, obj=None): - if not MockLocalObjectDataExtractor._session_data: + if not MockAPIHelper._session_data: with open( - str(Path(MockLocalObjectDataExtractor._session_dump).resolve()), + str(Path(MockAPIHelper._session_dump).resolve()), "rb", ) as pickle_obj: - MockLocalObjectDataExtractor._session_data = pickle.load(pickle_obj) - self.field_info = lambda: MockFieldInfo( - MockLocalObjectDataExtractor._session_data - ) + MockAPIHelper._session_data = pickle.load(pickle_obj) + self.field_info = lambda: MockFieldInfo(MockAPIHelper._session_data) self.field_data = lambda: MockFieldData( - MockLocalObjectDataExtractor._session_data, self.field_info + MockAPIHelper._session_data, self.field_info ) self.id = lambda: 1 @@ -178,8 +176,8 @@ def __init__(self, obj=None): def test_field_api(): pyvista_graphics = Graphics(session=None) contour1 = pyvista_graphics.Contours["contour-1"] - field_info = contour1._data_extractor.field_info() - field_data = contour1._data_extractor.field_data() + field_info = contour1._api_helper.field_info() + field_data = contour1._api_helper.field_data() surfaces_id = [ v["surface_id"][0] for k, v in field_info.get_surfaces_info().items() @@ -254,7 +252,7 @@ def test_contour_object(): pyvista_graphics = Graphics(session=None) contour1 = pyvista_graphics.Contours["contour-1"] - field_info = contour1._data_extractor.field_info() + field_info = contour1._api_helper.field_info() # Surfaces allowed values should be all surfaces. assert contour1.surfaces_list.allowed_values == list( @@ -273,9 +271,7 @@ def test_contour_object(): 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() - ] + assert contour1.field.allowed_values == list(field_info.get_fields_info()) # Important. Because there is no type checking so following passes. contour1.field = [contour1.field.allowed_values[0]] @@ -343,7 +339,7 @@ def test_vector_object(): pyvista_graphics = Graphics(session=None) vector1 = pyvista_graphics.Vectors["contour-1"] - field_info = vector1._data_extractor.field_info() + field_info = vector1._api_helper.field_info() assert vector1.surfaces_list.allowed_values == list( field_info.get_surfaces_info().keys() @@ -382,7 +378,7 @@ def test_surface_object(): pyvista_graphics = Graphics(session=None) surf1 = pyvista_graphics.Surfaces["surf-1"] - field_info = surf1._data_extractor.field_info() + field_info = surf1._api_helper.field_info() surf1.surface.type = "iso-surface" assert surf1.surface.plane_surface is None @@ -396,9 +392,7 @@ def test_surface_object(): surf1.surface.type = "iso-surface" iso_surf = surf1.surface.iso_surface - assert iso_surf.field.allowed_values == [ - v["solver_name"] for k, v in field_info.get_fields_info().items() - ] + assert iso_surf.field.allowed_values == list(field_info.get_fields_info()) # Important. Because there is no type checking so following test passes. iso_surf.field = [iso_surf.field.allowed_values[0]] @@ -456,7 +450,7 @@ def test_xyplot_object(): matplotlib_plots = Plots(session=None) p1 = matplotlib_plots.XYPlots["p-1"] - field_info = p1._data_extractor.field_info() + field_info = p1._api_helper.field_info() assert p1.surfaces_list.allowed_values == list( field_info.get_surfaces_info().keys() @@ -470,9 +464,7 @@ def test_xyplot_object(): p1.surfaces_list = p1.surfaces_list.allowed_values - assert p1.y_axis_function.allowed_values == [ - v["solver_name"] for k, v in field_info.get_fields_info().items() - ] + assert p1.y_axis_function.allowed_values == list(field_info.get_fields_info()) # Important. Because there is no type checking so following passes. p1.y_axis_function = [p1.y_axis_function.allowed_values[0]]