From 51e514f2601d8f7530f36fdad2814aabd7c6ccc7 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:00:08 +0200 Subject: [PATCH 01/17] feat: using only one instance of `save_selection`. --- src/ansys/mapdl/core/mapdl_core.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/ansys/mapdl/core/mapdl_core.py b/src/ansys/mapdl/core/mapdl_core.py index e4502ece48..b3ddc6ddfb 100644 --- a/src/ansys/mapdl/core/mapdl_core.py +++ b/src/ansys/mapdl/core/mapdl_core.py @@ -253,6 +253,7 @@ def __init__( self._default_file_type_for_plots = file_type_for_plots self._version = None # cached version self._mute = False + self._save_selection_obj = None if _HAS_PYVISTA: if use_vtk is not None: # pragma: no cover @@ -954,7 +955,9 @@ def save_selection(self): when exit returns to that selection. """ - return self._save_selection(self) + if self._save_selection_obj is None: + self._save_selection_obj = self._save_selection(self) + return self._save_selection_obj @property def solution(self) -> "Solution": @@ -1415,6 +1418,13 @@ def __exit__(self, *args): mapdl = self._parent() + # Restore first the components, and later entities; so the entities + # selection can be overwritten but the components still activated. + + # Mute to avoid getting issues when the component wasn't created in + # first place because there was no entities. + self._parent().components.select(last_selection_cmps, mute=True) + # probably this is redundant prev_ier = mapdl.ignore_errors mapdl.ignore_errors = True @@ -1425,10 +1435,6 @@ def __exit__(self, *args): mapdl.ignore_errors = prev_ier - # mute to avoid getting issues when the component wasn't created in - # first place because there was no entities. - self._parent().components.select(last_selection_cmps, mute=True) - class _chain_commands: """Store MAPDL commands and send one chained command.""" @@ -1440,7 +1446,7 @@ def __enter__(self): self._parent()._store_commands = True def __exit__(self, *args): - self._parent()._log.debug("Entering chained command mode") + self._parent()._log.debug("Exiting chained command mode") self._parent()._chain_stored() self._parent()._store_commands = False From 58dc3dc7e7a017b7a34560deac754d36e5e2337f Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:05:42 +0200 Subject: [PATCH 02/17] Revert "feat: using only one instance of `save_selection`." This reverts commit 51e514f2601d8f7530f36fdad2814aabd7c6ccc7. --- src/ansys/mapdl/core/mapdl_core.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/ansys/mapdl/core/mapdl_core.py b/src/ansys/mapdl/core/mapdl_core.py index b3ddc6ddfb..e4502ece48 100644 --- a/src/ansys/mapdl/core/mapdl_core.py +++ b/src/ansys/mapdl/core/mapdl_core.py @@ -253,7 +253,6 @@ def __init__( self._default_file_type_for_plots = file_type_for_plots self._version = None # cached version self._mute = False - self._save_selection_obj = None if _HAS_PYVISTA: if use_vtk is not None: # pragma: no cover @@ -955,9 +954,7 @@ def save_selection(self): when exit returns to that selection. """ - if self._save_selection_obj is None: - self._save_selection_obj = self._save_selection(self) - return self._save_selection_obj + return self._save_selection(self) @property def solution(self) -> "Solution": @@ -1418,13 +1415,6 @@ def __exit__(self, *args): mapdl = self._parent() - # Restore first the components, and later entities; so the entities - # selection can be overwritten but the components still activated. - - # Mute to avoid getting issues when the component wasn't created in - # first place because there was no entities. - self._parent().components.select(last_selection_cmps, mute=True) - # probably this is redundant prev_ier = mapdl.ignore_errors mapdl.ignore_errors = True @@ -1435,6 +1425,10 @@ def __exit__(self, *args): mapdl.ignore_errors = prev_ier + # mute to avoid getting issues when the component wasn't created in + # first place because there was no entities. + self._parent().components.select(last_selection_cmps, mute=True) + class _chain_commands: """Store MAPDL commands and send one chained command.""" @@ -1446,7 +1440,7 @@ def __enter__(self): self._parent()._store_commands = True def __exit__(self, *args): - self._parent()._log.debug("Exiting chained command mode") + self._parent()._log.debug("Entering chained command mode") self._parent()._chain_stored() self._parent()._store_commands = False From ae71ca55cf6a0cea1567d65cd0833bdc60f41136 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:00:08 +0200 Subject: [PATCH 03/17] fix: changing the ids, but not restoring correctly the components --- src/ansys/mapdl/core/mapdl_core.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/ansys/mapdl/core/mapdl_core.py b/src/ansys/mapdl/core/mapdl_core.py index e4502ece48..b3ddc6ddfb 100644 --- a/src/ansys/mapdl/core/mapdl_core.py +++ b/src/ansys/mapdl/core/mapdl_core.py @@ -253,6 +253,7 @@ def __init__( self._default_file_type_for_plots = file_type_for_plots self._version = None # cached version self._mute = False + self._save_selection_obj = None if _HAS_PYVISTA: if use_vtk is not None: # pragma: no cover @@ -954,7 +955,9 @@ def save_selection(self): when exit returns to that selection. """ - return self._save_selection(self) + if self._save_selection_obj is None: + self._save_selection_obj = self._save_selection(self) + return self._save_selection_obj @property def solution(self) -> "Solution": @@ -1415,6 +1418,13 @@ def __exit__(self, *args): mapdl = self._parent() + # Restore first the components, and later entities; so the entities + # selection can be overwritten but the components still activated. + + # Mute to avoid getting issues when the component wasn't created in + # first place because there was no entities. + self._parent().components.select(last_selection_cmps, mute=True) + # probably this is redundant prev_ier = mapdl.ignore_errors mapdl.ignore_errors = True @@ -1425,10 +1435,6 @@ def __exit__(self, *args): mapdl.ignore_errors = prev_ier - # mute to avoid getting issues when the component wasn't created in - # first place because there was no entities. - self._parent().components.select(last_selection_cmps, mute=True) - class _chain_commands: """Store MAPDL commands and send one chained command.""" @@ -1440,7 +1446,7 @@ def __enter__(self): self._parent()._store_commands = True def __exit__(self, *args): - self._parent()._log.debug("Entering chained command mode") + self._parent()._log.debug("Exiting chained command mode") self._parent()._chain_stored() self._parent()._store_commands = False From 0637a0c7c9236d998ad213ba1501b01ff9cb7ae0 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:07:54 +0200 Subject: [PATCH 04/17] refactor: small cosmetic changes --- src/ansys/mapdl/core/mapdl_extended.py | 9 +++++---- src/ansys/mapdl/core/mapdl_geometry.py | 21 +++++++++++---------- src/ansys/mapdl/core/mesh/mesh.py | 2 +- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/ansys/mapdl/core/mapdl_extended.py b/src/ansys/mapdl/core/mapdl_extended.py index 908ccdebae..56705b1d32 100644 --- a/src/ansys/mapdl/core/mapdl_extended.py +++ b/src/ansys/mapdl/core/mapdl_extended.py @@ -733,10 +733,11 @@ def aplot( pl.plot([], [], [], **kwargs) return pl.show(**kwargs) - if quality > 10: - quality = 10 - if quality < 1: - quality = 1 + if quality < 1 or quality > 10: + raise ValueError( + f"The argument 'quality' can only be a integer between 1 and 10 (included both)." + ) + surfs = self.geometry.get_areas(return_as_list=True, quality=quality) meshes = [] labels = [] diff --git a/src/ansys/mapdl/core/mapdl_geometry.py b/src/ansys/mapdl/core/mapdl_geometry.py index 58dacf70b0..e287f68d2e 100644 --- a/src/ansys/mapdl/core/mapdl_geometry.py +++ b/src/ansys/mapdl/core/mapdl_geometry.py @@ -650,24 +650,25 @@ def generate_surface( # reselect from existing selection to mimic APDL behavior if amin or amax: - if amax is None: - amax = amin - - if amin is None: # amax is non-zero - amin = 1 - - if ninc is None: - ninc = "" + amax = amax or amin + amin = amin or 1 + ninc = ninc or "" self._mapdl.asel("R", "AREA", vmin=amin, vmax=amax, vinc=ninc) + ## Duplication # duplicate areas to avoid affecting existing areas + # Getting the maximum area ID a_num = int(self._mapdl.get(entity="AREA", item1="NUM", it1num="MAXD")) + # Setting the new areas ID starting number self._mapdl.numstr("AREA", a_num, mute=True) + # Generating new areas self._mapdl.agen(2, "ALL", noelem=1, mute=True) - a_max = int(self._mapdl.get(entity="AREA", item1="NUM", it1num="MAXD")) + # Getting the new maximum area ID + a_max = int(self._mapdl.get(entity="AREA", item1="NUM", it1num="MAXD")) self._mapdl.asel("S", "AREA", vmin=a_num + 1, vmax=a_max, mute=True) + # necessary to reset element/area meshing association self._mapdl.aatt(mute=True) @@ -687,7 +688,7 @@ def generate_surface( self._mapdl.prep7(mute=True) # Mesh and get the number of elements per area - resp = self._mapdl.amesh("all") + self._mapdl.amesh("all", mute=True) elements_per_area = self.get_elements_per_area() self._mapdl.esla("S") diff --git a/src/ansys/mapdl/core/mesh/mesh.py b/src/ansys/mapdl/core/mesh/mesh.py index 6df042cd05..6853d237d6 100644 --- a/src/ansys/mapdl/core/mesh/mesh.py +++ b/src/ansys/mapdl/core/mesh/mesh.py @@ -112,7 +112,7 @@ def _parse_vtk( """ if not mesh._has_nodes or not mesh._has_elements: # warnings.warn('Missing nodes or elements. Unable to parse to vtk') - return + return pv.UnstructuredGrid() etype_map = ETYPE_MAP if allowable_types is not None: From fd8ced4c545f2d674c5798bb9e97e8e56f24d1f3 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:08:29 +0200 Subject: [PATCH 05/17] tests: adding tests --- tests/test_plotting.py | 117 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/tests/test_plotting.py b/tests/test_plotting.py index d35ae176fa..c67e784c73 100644 --- a/tests/test_plotting.py +++ b/tests/test_plotting.py @@ -111,6 +111,43 @@ def block_example_coupled(mapdl): mapdl.n(3, 2, 0, 0) +def check_geometry(mapdl, function): + prev_knum = mapdl.geometry.knum + prev_lnum = mapdl.geometry.lnum + prev_anum = mapdl.geometry.anum + prev_kps = mapdl.geometry.get_keypoints( + return_as_array=True, return_ids_in_array=True + ) + prev_lines = mapdl.geometry.get_lines(return_as_list=True) + prev_areas = mapdl.geometry.get_areas(return_as_list=True) + + out = function() + + new_knum = mapdl.geometry.knum + new_lnum = mapdl.geometry.lnum + new_anum = mapdl.geometry.anum + new_kps = mapdl.geometry.get_keypoints( + return_as_array=True, return_ids_in_array=True + ) + new_lines = mapdl.geometry.get_lines(return_as_list=True) + new_areas = mapdl.geometry.get_areas(return_as_list=True) + + assert np.allclose(prev_knum, new_knum) + assert np.allclose(prev_lnum, new_lnum) + assert np.allclose(prev_anum, new_anum) + assert len(prev_kps) == len(new_kps) + assert len(prev_lines) == len(new_lines) + assert len(prev_areas) == len(new_areas) + assert all([each in new_kps for each in prev_kps]) + assert all([each in new_lines for each in prev_lines]) + assert all([each in new_areas for each in prev_areas]) + assert all([each in prev_kps for each in new_kps]) + assert all([each in prev_lines for each in new_lines]) + assert all([each in prev_areas for each in new_areas]) + + return out + + def test_plot_empty_mesh(mapdl, cleared): with pytest.warns(UserWarning): mapdl.nplot(vtk=True) @@ -1126,3 +1163,83 @@ def test_lplot_line(mapdl, cleared): mapdl.lplot( show_line_numbering=False, show_keypoint_numbering=True, color_lines=True ) + + +@pytest.mark.parametrize( + "func,entity", + [("vplot", "VOLU"), ("aplot", "AREA"), ("lplot", "LINE"), ("kplot", "KP")], +) +@pytest.mark.parametrize("partial", [True, False]) +def test_xplot_not_changing_geo_selection(mapdl, cleared, func, entity, partial): + mapdl.prep7() + mapdl.block(0, 1, 0, 1, 0, 1) + mapdl.block(1, 2, 1, 2, 1, 2) + mapdl.block(2, 3, 2, 3, 2, 3) + + mapdl.geometry._select_items(1, entity, "S") + mapdl.cm("selection1", entity) + mapdl.cmsel("u", "selection1") + + mapdl.geometry._select_items(2, entity, "S") + mapdl.cm("selection2", entity) + + if not partial: + mapdl.allsel() + mapdl.cmsel("all") + + fn = getattr(mapdl, func) + check_geometry(mapdl, fn) + + +def test_xplot_not_changing_geo_selection2(mapdl, cleared): + mapdl.prep7() + mapdl.rectng(0, 1, 0, 1) + mapdl.cm("area1", "area") + mapdl.cmsel("u", "area1") + mapdl.rectng(2, 4, -1, 1) + mapdl.cm("area2", "area") + mapdl.allsel() + mapdl.cmsel("all") + + check_geometry(mapdl, mapdl.aplot) + + +@pytest.mark.parametrize( + "plot_func,entity,gen_func,arg1,arg2", + [ + ("vplot", "VOLU", "block", (0, 1, 0, 1, 0, 1), (1, 2, 1, 2, 1, 2)), + ("aplot", "AREA", "rectng", (0, 1, 0, 1), (1, 2, 1, 2)), + ("lplot", "LINE", "slashline", (1, 1, 1), (1, -1, 1)), + ("kplot", "KP", "k", ("", 0, 0, 0), ("", 1, 1, 1)), + ], +) +def test_xplot_not_changing_geo_selection_components( + mapdl, cleared, plot_func, entity, gen_func, arg1, arg2 +): + mapdl.prep7() + gen_func = getattr(mapdl, gen_func) + + if entity == "LINE": + l0 = mapdl.k("", (0, 0, 0, 0)) + l1 = mapdl.k("", *arg1) + mapdl.l(l0, l1) + else: + gen_func(*arg1) + + mapdl.cm("select1", entity) + mapdl.cmsel("u", "select1") + + if entity == "LINE": + l0 = mapdl.k("", (0, 0, 0, 0)) + l1 = mapdl.k("", *arg2) + mapdl.l(l0, l1) + else: + gen_func(*arg2) + + mapdl.cm("select2", entity) + + mapdl.allsel() + mapdl.cmsel("all") + + plot_func = getattr(mapdl, plot_func) + check_geometry(mapdl, plot_func) From b16b4720e1322ef23a676bb037f70ce3b219f1b0 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:10:22 +0200 Subject: [PATCH 06/17] revert: avoiding mute amesh. --- src/ansys/mapdl/core/mapdl_geometry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/mapdl_geometry.py b/src/ansys/mapdl/core/mapdl_geometry.py index e287f68d2e..29f847ba88 100644 --- a/src/ansys/mapdl/core/mapdl_geometry.py +++ b/src/ansys/mapdl/core/mapdl_geometry.py @@ -688,7 +688,7 @@ def generate_surface( self._mapdl.prep7(mute=True) # Mesh and get the number of elements per area - self._mapdl.amesh("all", mute=True) + resp = self._mapdl.amesh("all") elements_per_area = self.get_elements_per_area() self._mapdl.esla("S") From a2fef3e4fa9a229367fccbf8b6907f98c023efa8 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:00:08 +0200 Subject: [PATCH 07/17] feat: using only one instance of `save_selection`. --- src/ansys/mapdl/core/mapdl_core.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/ansys/mapdl/core/mapdl_core.py b/src/ansys/mapdl/core/mapdl_core.py index e4502ece48..b3ddc6ddfb 100644 --- a/src/ansys/mapdl/core/mapdl_core.py +++ b/src/ansys/mapdl/core/mapdl_core.py @@ -253,6 +253,7 @@ def __init__( self._default_file_type_for_plots = file_type_for_plots self._version = None # cached version self._mute = False + self._save_selection_obj = None if _HAS_PYVISTA: if use_vtk is not None: # pragma: no cover @@ -954,7 +955,9 @@ def save_selection(self): when exit returns to that selection. """ - return self._save_selection(self) + if self._save_selection_obj is None: + self._save_selection_obj = self._save_selection(self) + return self._save_selection_obj @property def solution(self) -> "Solution": @@ -1415,6 +1418,13 @@ def __exit__(self, *args): mapdl = self._parent() + # Restore first the components, and later entities; so the entities + # selection can be overwritten but the components still activated. + + # Mute to avoid getting issues when the component wasn't created in + # first place because there was no entities. + self._parent().components.select(last_selection_cmps, mute=True) + # probably this is redundant prev_ier = mapdl.ignore_errors mapdl.ignore_errors = True @@ -1425,10 +1435,6 @@ def __exit__(self, *args): mapdl.ignore_errors = prev_ier - # mute to avoid getting issues when the component wasn't created in - # first place because there was no entities. - self._parent().components.select(last_selection_cmps, mute=True) - class _chain_commands: """Store MAPDL commands and send one chained command.""" @@ -1440,7 +1446,7 @@ def __enter__(self): self._parent()._store_commands = True def __exit__(self, *args): - self._parent()._log.debug("Entering chained command mode") + self._parent()._log.debug("Exiting chained command mode") self._parent()._chain_stored() self._parent()._store_commands = False From 7fdf8d7d8a145532cb6e8cf1a9c70c40fa5aee69 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:05:42 +0200 Subject: [PATCH 08/17] Revert "feat: using only one instance of `save_selection`." This reverts commit 51e514f2601d8f7530f36fdad2814aabd7c6ccc7. --- src/ansys/mapdl/core/mapdl_core.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/ansys/mapdl/core/mapdl_core.py b/src/ansys/mapdl/core/mapdl_core.py index b3ddc6ddfb..e4502ece48 100644 --- a/src/ansys/mapdl/core/mapdl_core.py +++ b/src/ansys/mapdl/core/mapdl_core.py @@ -253,7 +253,6 @@ def __init__( self._default_file_type_for_plots = file_type_for_plots self._version = None # cached version self._mute = False - self._save_selection_obj = None if _HAS_PYVISTA: if use_vtk is not None: # pragma: no cover @@ -955,9 +954,7 @@ def save_selection(self): when exit returns to that selection. """ - if self._save_selection_obj is None: - self._save_selection_obj = self._save_selection(self) - return self._save_selection_obj + return self._save_selection(self) @property def solution(self) -> "Solution": @@ -1418,13 +1415,6 @@ def __exit__(self, *args): mapdl = self._parent() - # Restore first the components, and later entities; so the entities - # selection can be overwritten but the components still activated. - - # Mute to avoid getting issues when the component wasn't created in - # first place because there was no entities. - self._parent().components.select(last_selection_cmps, mute=True) - # probably this is redundant prev_ier = mapdl.ignore_errors mapdl.ignore_errors = True @@ -1435,6 +1425,10 @@ def __exit__(self, *args): mapdl.ignore_errors = prev_ier + # mute to avoid getting issues when the component wasn't created in + # first place because there was no entities. + self._parent().components.select(last_selection_cmps, mute=True) + class _chain_commands: """Store MAPDL commands and send one chained command.""" @@ -1446,7 +1440,7 @@ def __enter__(self): self._parent()._store_commands = True def __exit__(self, *args): - self._parent()._log.debug("Exiting chained command mode") + self._parent()._log.debug("Entering chained command mode") self._parent()._chain_stored() self._parent()._store_commands = False From 9a160da8f3e8dbc0d7551f9dd834c8e0c5d1e55c Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:00:08 +0200 Subject: [PATCH 09/17] fix: changing the ids, but not restoring correctly the components --- src/ansys/mapdl/core/mapdl_core.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/ansys/mapdl/core/mapdl_core.py b/src/ansys/mapdl/core/mapdl_core.py index e4502ece48..b3ddc6ddfb 100644 --- a/src/ansys/mapdl/core/mapdl_core.py +++ b/src/ansys/mapdl/core/mapdl_core.py @@ -253,6 +253,7 @@ def __init__( self._default_file_type_for_plots = file_type_for_plots self._version = None # cached version self._mute = False + self._save_selection_obj = None if _HAS_PYVISTA: if use_vtk is not None: # pragma: no cover @@ -954,7 +955,9 @@ def save_selection(self): when exit returns to that selection. """ - return self._save_selection(self) + if self._save_selection_obj is None: + self._save_selection_obj = self._save_selection(self) + return self._save_selection_obj @property def solution(self) -> "Solution": @@ -1415,6 +1418,13 @@ def __exit__(self, *args): mapdl = self._parent() + # Restore first the components, and later entities; so the entities + # selection can be overwritten but the components still activated. + + # Mute to avoid getting issues when the component wasn't created in + # first place because there was no entities. + self._parent().components.select(last_selection_cmps, mute=True) + # probably this is redundant prev_ier = mapdl.ignore_errors mapdl.ignore_errors = True @@ -1425,10 +1435,6 @@ def __exit__(self, *args): mapdl.ignore_errors = prev_ier - # mute to avoid getting issues when the component wasn't created in - # first place because there was no entities. - self._parent().components.select(last_selection_cmps, mute=True) - class _chain_commands: """Store MAPDL commands and send one chained command.""" @@ -1440,7 +1446,7 @@ def __enter__(self): self._parent()._store_commands = True def __exit__(self, *args): - self._parent()._log.debug("Entering chained command mode") + self._parent()._log.debug("Exiting chained command mode") self._parent()._chain_stored() self._parent()._store_commands = False From 229abaa64482cdaf24e7c14506e6bdbe1096f7f7 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:07:54 +0200 Subject: [PATCH 10/17] refactor: small cosmetic changes --- src/ansys/mapdl/core/mapdl_extended.py | 9 +++++---- src/ansys/mapdl/core/mapdl_geometry.py | 21 +++++++++++---------- src/ansys/mapdl/core/mesh/mesh.py | 2 +- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/ansys/mapdl/core/mapdl_extended.py b/src/ansys/mapdl/core/mapdl_extended.py index 908ccdebae..56705b1d32 100644 --- a/src/ansys/mapdl/core/mapdl_extended.py +++ b/src/ansys/mapdl/core/mapdl_extended.py @@ -733,10 +733,11 @@ def aplot( pl.plot([], [], [], **kwargs) return pl.show(**kwargs) - if quality > 10: - quality = 10 - if quality < 1: - quality = 1 + if quality < 1 or quality > 10: + raise ValueError( + f"The argument 'quality' can only be a integer between 1 and 10 (included both)." + ) + surfs = self.geometry.get_areas(return_as_list=True, quality=quality) meshes = [] labels = [] diff --git a/src/ansys/mapdl/core/mapdl_geometry.py b/src/ansys/mapdl/core/mapdl_geometry.py index 58dacf70b0..e287f68d2e 100644 --- a/src/ansys/mapdl/core/mapdl_geometry.py +++ b/src/ansys/mapdl/core/mapdl_geometry.py @@ -650,24 +650,25 @@ def generate_surface( # reselect from existing selection to mimic APDL behavior if amin or amax: - if amax is None: - amax = amin - - if amin is None: # amax is non-zero - amin = 1 - - if ninc is None: - ninc = "" + amax = amax or amin + amin = amin or 1 + ninc = ninc or "" self._mapdl.asel("R", "AREA", vmin=amin, vmax=amax, vinc=ninc) + ## Duplication # duplicate areas to avoid affecting existing areas + # Getting the maximum area ID a_num = int(self._mapdl.get(entity="AREA", item1="NUM", it1num="MAXD")) + # Setting the new areas ID starting number self._mapdl.numstr("AREA", a_num, mute=True) + # Generating new areas self._mapdl.agen(2, "ALL", noelem=1, mute=True) - a_max = int(self._mapdl.get(entity="AREA", item1="NUM", it1num="MAXD")) + # Getting the new maximum area ID + a_max = int(self._mapdl.get(entity="AREA", item1="NUM", it1num="MAXD")) self._mapdl.asel("S", "AREA", vmin=a_num + 1, vmax=a_max, mute=True) + # necessary to reset element/area meshing association self._mapdl.aatt(mute=True) @@ -687,7 +688,7 @@ def generate_surface( self._mapdl.prep7(mute=True) # Mesh and get the number of elements per area - resp = self._mapdl.amesh("all") + self._mapdl.amesh("all", mute=True) elements_per_area = self.get_elements_per_area() self._mapdl.esla("S") diff --git a/src/ansys/mapdl/core/mesh/mesh.py b/src/ansys/mapdl/core/mesh/mesh.py index 6df042cd05..6853d237d6 100644 --- a/src/ansys/mapdl/core/mesh/mesh.py +++ b/src/ansys/mapdl/core/mesh/mesh.py @@ -112,7 +112,7 @@ def _parse_vtk( """ if not mesh._has_nodes or not mesh._has_elements: # warnings.warn('Missing nodes or elements. Unable to parse to vtk') - return + return pv.UnstructuredGrid() etype_map = ETYPE_MAP if allowable_types is not None: From 5bb18e6a7612017c8df3a69eb34ac2e320a72c88 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:08:29 +0200 Subject: [PATCH 11/17] tests: adding tests --- tests/test_plotting.py | 117 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/tests/test_plotting.py b/tests/test_plotting.py index d35ae176fa..c67e784c73 100644 --- a/tests/test_plotting.py +++ b/tests/test_plotting.py @@ -111,6 +111,43 @@ def block_example_coupled(mapdl): mapdl.n(3, 2, 0, 0) +def check_geometry(mapdl, function): + prev_knum = mapdl.geometry.knum + prev_lnum = mapdl.geometry.lnum + prev_anum = mapdl.geometry.anum + prev_kps = mapdl.geometry.get_keypoints( + return_as_array=True, return_ids_in_array=True + ) + prev_lines = mapdl.geometry.get_lines(return_as_list=True) + prev_areas = mapdl.geometry.get_areas(return_as_list=True) + + out = function() + + new_knum = mapdl.geometry.knum + new_lnum = mapdl.geometry.lnum + new_anum = mapdl.geometry.anum + new_kps = mapdl.geometry.get_keypoints( + return_as_array=True, return_ids_in_array=True + ) + new_lines = mapdl.geometry.get_lines(return_as_list=True) + new_areas = mapdl.geometry.get_areas(return_as_list=True) + + assert np.allclose(prev_knum, new_knum) + assert np.allclose(prev_lnum, new_lnum) + assert np.allclose(prev_anum, new_anum) + assert len(prev_kps) == len(new_kps) + assert len(prev_lines) == len(new_lines) + assert len(prev_areas) == len(new_areas) + assert all([each in new_kps for each in prev_kps]) + assert all([each in new_lines for each in prev_lines]) + assert all([each in new_areas for each in prev_areas]) + assert all([each in prev_kps for each in new_kps]) + assert all([each in prev_lines for each in new_lines]) + assert all([each in prev_areas for each in new_areas]) + + return out + + def test_plot_empty_mesh(mapdl, cleared): with pytest.warns(UserWarning): mapdl.nplot(vtk=True) @@ -1126,3 +1163,83 @@ def test_lplot_line(mapdl, cleared): mapdl.lplot( show_line_numbering=False, show_keypoint_numbering=True, color_lines=True ) + + +@pytest.mark.parametrize( + "func,entity", + [("vplot", "VOLU"), ("aplot", "AREA"), ("lplot", "LINE"), ("kplot", "KP")], +) +@pytest.mark.parametrize("partial", [True, False]) +def test_xplot_not_changing_geo_selection(mapdl, cleared, func, entity, partial): + mapdl.prep7() + mapdl.block(0, 1, 0, 1, 0, 1) + mapdl.block(1, 2, 1, 2, 1, 2) + mapdl.block(2, 3, 2, 3, 2, 3) + + mapdl.geometry._select_items(1, entity, "S") + mapdl.cm("selection1", entity) + mapdl.cmsel("u", "selection1") + + mapdl.geometry._select_items(2, entity, "S") + mapdl.cm("selection2", entity) + + if not partial: + mapdl.allsel() + mapdl.cmsel("all") + + fn = getattr(mapdl, func) + check_geometry(mapdl, fn) + + +def test_xplot_not_changing_geo_selection2(mapdl, cleared): + mapdl.prep7() + mapdl.rectng(0, 1, 0, 1) + mapdl.cm("area1", "area") + mapdl.cmsel("u", "area1") + mapdl.rectng(2, 4, -1, 1) + mapdl.cm("area2", "area") + mapdl.allsel() + mapdl.cmsel("all") + + check_geometry(mapdl, mapdl.aplot) + + +@pytest.mark.parametrize( + "plot_func,entity,gen_func,arg1,arg2", + [ + ("vplot", "VOLU", "block", (0, 1, 0, 1, 0, 1), (1, 2, 1, 2, 1, 2)), + ("aplot", "AREA", "rectng", (0, 1, 0, 1), (1, 2, 1, 2)), + ("lplot", "LINE", "slashline", (1, 1, 1), (1, -1, 1)), + ("kplot", "KP", "k", ("", 0, 0, 0), ("", 1, 1, 1)), + ], +) +def test_xplot_not_changing_geo_selection_components( + mapdl, cleared, plot_func, entity, gen_func, arg1, arg2 +): + mapdl.prep7() + gen_func = getattr(mapdl, gen_func) + + if entity == "LINE": + l0 = mapdl.k("", (0, 0, 0, 0)) + l1 = mapdl.k("", *arg1) + mapdl.l(l0, l1) + else: + gen_func(*arg1) + + mapdl.cm("select1", entity) + mapdl.cmsel("u", "select1") + + if entity == "LINE": + l0 = mapdl.k("", (0, 0, 0, 0)) + l1 = mapdl.k("", *arg2) + mapdl.l(l0, l1) + else: + gen_func(*arg2) + + mapdl.cm("select2", entity) + + mapdl.allsel() + mapdl.cmsel("all") + + plot_func = getattr(mapdl, plot_func) + check_geometry(mapdl, plot_func) From dd3e2d66680e0fbb4414322f22a83e63bbae1494 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:10:22 +0200 Subject: [PATCH 12/17] revert: avoiding mute amesh. --- src/ansys/mapdl/core/mapdl_geometry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/mapdl_geometry.py b/src/ansys/mapdl/core/mapdl_geometry.py index e287f68d2e..29f847ba88 100644 --- a/src/ansys/mapdl/core/mapdl_geometry.py +++ b/src/ansys/mapdl/core/mapdl_geometry.py @@ -688,7 +688,7 @@ def generate_surface( self._mapdl.prep7(mute=True) # Mesh and get the number of elements per area - self._mapdl.amesh("all", mute=True) + resp = self._mapdl.amesh("all") elements_per_area = self.get_elements_per_area() self._mapdl.esla("S") From d3cf1f568d96c563b076b52771a0d1490fc59dc4 Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:17:21 +0000 Subject: [PATCH 13/17] chore: adding changelog file 3421.fixed.md --- doc/changelog.d/3421.fixed.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changelog.d/3421.fixed.md diff --git a/doc/changelog.d/3421.fixed.md b/doc/changelog.d/3421.fixed.md new file mode 100644 index 0000000000..59f222e7a5 --- /dev/null +++ b/doc/changelog.d/3421.fixed.md @@ -0,0 +1 @@ +fix/changing entities ids after plotting \ No newline at end of file From 6f139114576d18ee1e1c9aa674bfc015c08a1fb1 Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:23:18 +0000 Subject: [PATCH 14/17] chore: adding changelog file 3421.fixed.md --- doc/changelog.d/3421.fixed.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelog.d/3421.fixed.md b/doc/changelog.d/3421.fixed.md index 59f222e7a5..336b8458eb 100644 --- a/doc/changelog.d/3421.fixed.md +++ b/doc/changelog.d/3421.fixed.md @@ -1 +1 @@ -fix/changing entities ids after plotting \ No newline at end of file +fix: avoid changing entities ids after plotting \ No newline at end of file From 96343fc752da94da34086beb7769e92596503ed8 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Fri, 20 Sep 2024 18:10:36 +0200 Subject: [PATCH 15/17] doc: typos --- doc/source/user_guide/components.rst | 10 +++++----- src/ansys/mapdl/core/component.py | 8 +++++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/doc/source/user_guide/components.rst b/doc/source/user_guide/components.rst index 4b0e8603d9..3c606eb099 100644 --- a/doc/source/user_guide/components.rst +++ b/doc/source/user_guide/components.rst @@ -6,7 +6,7 @@ Managing components ******************* MAPDL components can be retrieved and set using -:attr:`Mapdl.components `. +:attr:`Mapdl.components `. There are several ways to create a component in MAPDL. @@ -42,7 +42,7 @@ Set a component without specifying the type, by default it is ``NODE``: warnings.warn( You can change the default type by changing -:attr:`Mapdl.components.default_entity ` +:attr:`Mapdl.components.default_entity ` .. code:: pycon @@ -78,10 +78,10 @@ Selecting a component and retrieving it: Component object ================ -The `Component object ` is the object returned by +The :class:`Component object ` is the object returned by :attr:`Mapdl.components ` when you query it with a component name. -This object has two main attributes: `type ` and `items `. -The former returns the component type (`"ELEM"`, `"NODE"`, `"KP"`, etc) and the later returns +This object has two main attributes: :attr:`type ` and :attr:`items `. +The former returns the component type (``"ELEM"``, ``"NODE"``, ``"KP"``, etc) and the later returns a tuple with the index of the entities which belong to that component. .. code:: pycon diff --git a/src/ansys/mapdl/core/component.py b/src/ansys/mapdl/core/component.py index c67eb6def5..d04fbcc392 100644 --- a/src/ansys/mapdl/core/component.py +++ b/src/ansys/mapdl/core/component.py @@ -177,8 +177,8 @@ class ComponentManager: ----- **Components need to be selected** using - :attr:`Mapdl.cmsel() ` before - being listed in :attr:`Mapdl.components ` + :attr:`Mapdl.cmsel() ` before being listed in + :class:`Mapdl.components ` Examples -------- @@ -507,7 +507,9 @@ def items(self): """ return self._comp.items() - def select(self, names: Union[str, list[str], tuple[str]], mute=False) -> None: + def select( + self, names: Union[str, list[str], tuple[str]], mute: bool = False + ) -> None: """Select Select components given their names Select components given their names. From 0f9ad5bb6fb9d6a045c923cf500517a46d78dfb5 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Fri, 20 Sep 2024 21:02:31 +0200 Subject: [PATCH 16/17] refactor: Avoiding components for saving selections or for performing multiple selections. --- src/ansys/mapdl/core/mapdl_core.py | 72 +++++++++++++----------------- 1 file changed, 30 insertions(+), 42 deletions(-) diff --git a/src/ansys/mapdl/core/mapdl_core.py b/src/ansys/mapdl/core/mapdl_core.py index b3ddc6ddfb..961f73ef65 100644 --- a/src/ansys/mapdl/core/mapdl_core.py +++ b/src/ansys/mapdl/core/mapdl_core.py @@ -1393,47 +1393,40 @@ class _save_selection: def __init__(self, parent): self._parent = weakref.ref(parent) - self.selection_sets = [] - self.selection_sets_comps = [] + self.selection = [] def __enter__(self): self._parent()._log.debug("Entering saving selection context") - - selection_set_name = random_string(10) - self.selection_sets.append(selection_set_name) - self.selection_sets_comps.append(self._parent().components.names) - mapdl = self._parent() - prev_ier = mapdl.ignore_errors - mapdl.ignore_errors = True - for entity in ["kp", "lines", "area", "volu", "node", "elem"]: - mapdl.cm(f"_{selection_set_name}_{entity}_", f"{entity}", mute=True) - mapdl.ignore_errors = prev_ier + # Storing components + selection = { + "cmsel": mapdl.components.names, + # "components_type": mapdl.components.types, + "nsel": mapdl.mesh.nnum, + "esel": mapdl.mesh.enum, + "ksel": mapdl.geometry.knum, + "lsel": mapdl.geometry.lnum, + "asel": mapdl.geometry.anum, + "vsel": mapdl.geometry.vnum, + } + + self.selection.append(selection) def __exit__(self, *args): self._parent()._log.debug("Exiting saving selection context") - last_selection_name = self.selection_sets.pop() - last_selection_cmps = self.selection_sets_comps.pop() - + selection = self.selection.pop() mapdl = self._parent() - # Restore first the components, and later entities; so the entities - # selection can be overwritten but the components still activated. - - # Mute to avoid getting issues when the component wasn't created in - # first place because there was no entities. - self._parent().components.select(last_selection_cmps, mute=True) + cmps = selection.pop("cmsel") - # probably this is redundant - prev_ier = mapdl.ignore_errors - mapdl.ignore_errors = True - for entity in ["kp", "lines", "area", "volu", "node", "elem"]: - cmp_name = f"_{last_selection_name}_{entity}_" - mapdl.cmsel("s", cmp_name, f"{entity}", mute=True) - mapdl.cmdele(cmp_name) + if cmps: + mapdl.components.select(cmps) - mapdl.ignore_errors = prev_ier + for select_cmd, ids in selection.items(): + if ids.size > 0: + func = getattr(mapdl, select_cmd) + func(vmin=ids) class _chain_commands: """Store MAPDL commands and send one chained command.""" @@ -2706,22 +2699,17 @@ def _perform_entity_list_selection( self, entity, selection_function, type_, item, comp, vmin, kabs ): """Select entities using CM, and the supplied selection function.""" - self.cm(f"__temp_{entity}s__", f"{entity}") # Saving previous selection - # Getting new selection for id_, each_ in enumerate(vmin): - selection_function( - self, "S" if id_ == 0 else "A", item, comp, each_, "", "", kabs - ) - - self.cm(f"__temp_{entity}s_1__", f"{entity}") - - self.cmsel("S", f"__temp_{entity}s__") - self.cmsel(type_, f"__temp_{entity}s_1__") + if type_ == "S" or not type_: + type__ = "S" if id_ == 0 else "A" + # R is an issue, because first iteration will clean up the rest. + elif type_ == "R": + raise NotImplementedError("Mode R is not supported.") + else: + type__ = type_ - # Cleaning - self.cmdele(f"__temp_{entity}s__") - self.cmdele(f"__temp_{entity}s_1__") + selection_function(self, type__, item, comp, each_, "", "", kabs) def _raise_errors(self, text): # to make sure the following error messages are caught even if a breakline is in between. From 894f8393e01ef61cf455be1677d6e11a33b9b1cb Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Fri, 20 Sep 2024 21:21:41 +0200 Subject: [PATCH 17/17] fix: test and adding test for quality --- tests/test_plotting.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/test_plotting.py b/tests/test_plotting.py index c67e784c73..d8b48ea447 100644 --- a/tests/test_plotting.py +++ b/tests/test_plotting.py @@ -255,7 +255,7 @@ def test_aplot(cleared, mapdl, vtk): mapdl.aplot(show_area_numbering=True) mapdl.aplot(vtk=vtk, color_areas=vtk, show_lines=True, show_line_numbering=True) - mapdl.aplot(quality=100) + mapdl.aplot(quality=10) mapdl.aplot(quality=-1) @@ -1243,3 +1243,12 @@ def test_xplot_not_changing_geo_selection_components( plot_func = getattr(mapdl, plot_func) check_geometry(mapdl, plot_func) + + +@pytest.mark.parametrize("quality", [101, -2, 0, "as"]) +def test_aplot_quality_fail(mapdl, block, quality): + with pytest.raises( + ValueError, + match="The argument 'quality' can only be a integer between 1 and 10 (included both)", + ): + mapdl.aplot(quality=quality)