-
Notifications
You must be signed in to change notification settings - Fork 12
Mesh splitting and selection #346
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 105 commits
bbf18e7
6995be2
0bc4c45
d3add0e
d135076
dfb6983
87195ea
0fe0cdd
b7eb6c8
f575069
3b0edf0
d1ccfad
500d711
72accfc
94d9df0
1396828
955ef07
ce7fa1e
e746560
5fac5d7
2caad5b
07e37fd
5f254b7
85957ab
37814c6
f0a516d
50745c6
8eb03ab
9ecfcc5
e55da83
3f26763
2415afe
c732e38
a610f61
23d9989
913188c
1fd41aa
217777e
f107ab5
56f1c5d
d8e8414
7b64975
ccec46b
6dca2f8
befe782
5d56699
4eba411
e81da71
c9f07a2
0bde530
30f8186
4a38217
a1fd26c
97e13fe
15325e1
a9316a3
19a4452
354cd08
76507ba
29daf4a
c627349
d5e0630
474fbf3
c0e9e04
026cee4
b2611c8
cfacf69
b7ec61d
80bd4b6
44e00ad
8d26130
22f92cf
a925508
4438389
3e17d35
9d19ab6
0f22b79
91ba3aa
c09459b
f628c3f
9c6a732
7b2dc6d
98a070b
110efbe
2b6b351
8725827
9ba9345
8e5ff1a
d207d37
7fd3e0e
baeef13
a6aebe9
775433d
3dab0c5
f4dd528
d0bffb3
747b889
7536af0
a4bf121
9b215bf
83e35af
7ea1b89
c3ae713
7d132e7
19f2149
3e271a4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,222 @@ | ||
| """ | ||
| .. _ref_mesh_exploration_example: | ||
|
|
||
| Explore the mesh | ||
| ================ | ||
| This example shows how to explore and manipulate the mesh object to query mesh data | ||
| such as connectivity tables, element IDs, element types and so on. | ||
| """ | ||
|
|
||
| ############################################################################### | ||
| # Perform required imports | ||
| # ------------------------ | ||
| # Perform required imports. | ||
| # This example uses a supplied file that you can | ||
| # get by importing the DPF ``examples`` package. | ||
|
|
||
| from ansys.dpf import post | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as we discussed @ansys-akarcher, in my opinion this is not really an example, it's more an api display, if you could move these to the mesh docstrings, it would be great
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI @PProfizi
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @cbellot000 yes, I just added examples in dosctrings of post.Mesh |
||
| from ansys.dpf.post import examples | ||
| from ansys.dpf.post.common import elemental_properties | ||
|
|
||
| ############################################################################### | ||
| # Load the result file | ||
| # -------------------- | ||
| # Load the result file in a ``Simulation`` object that allows access to the results. | ||
| # The ``Simulation`` object must be instantiated with the path for the result file. | ||
| # For example, ``"C:/Users/user/my_result.rst"`` on Windows | ||
| # or ``"/home/user/my_result.rst"`` on Linux. | ||
|
|
||
| example_path = examples.download_harmonic_clamped_pipe() | ||
| simulation = post.HarmonicMechanicalSimulation(example_path) | ||
|
|
||
| ############################################################################### | ||
| # Get the mesh | ||
| # ------------ | ||
| # Retrieve the mesh | ||
| mesh = simulation.mesh | ||
| # Printing the mesh directly gives the same information already shown at the simulation level | ||
| print(mesh) | ||
|
|
||
| ############################################################################### | ||
| # Plot the mesh | ||
| # ------------- | ||
| # Plot the mesh to view the bare mesh of the model | ||
| mesh.plot() | ||
|
|
||
| #################################################################q############## | ||
| # Query basic information about the mesh | ||
| # -------------------------------------- | ||
| # The ``Mesh`` object has several properties allowing access to different information such as: | ||
|
|
||
| # the number of nodes | ||
| print(f"This mesh contains {mesh.num_nodes} nodes") | ||
|
|
||
| # the list of node IDs | ||
| print(f"with IDs: {mesh.node_ids}.") | ||
|
|
||
| # the number of elements | ||
| print(f"This mesh contains {mesh.num_elements} elements") | ||
|
|
||
| # the list of element IDs | ||
| print(f"with IDs {mesh.element_ids}.") | ||
|
|
||
| # the unit of the mesh | ||
| print(f"The mesh is in '{mesh.unit}'.") | ||
|
|
||
| ############################################################################### | ||
| # Named selections | ||
| # ---------------- | ||
| # The available named selections are given as a dictionary | ||
| # with the names as keys and the actual ``NamedSelection`` objects as values. | ||
| # Printing the dictionary informs you on the available names. | ||
| named_selections = mesh.named_selections | ||
| print(named_selections) | ||
|
|
||
| ############################################################################### | ||
| # To get a specific named selection, query it using its name as key | ||
| print(named_selections["_FIXEDSU"]) | ||
|
|
||
| ############################################################################### | ||
| # Elements | ||
| # -------- | ||
| # Use ``mesh.elements`` to access the list of Element objects | ||
| print(mesh.elements) | ||
|
|
||
| ############################################################################### | ||
| # You can then query a specific element by its ID | ||
| print(mesh.elements.by_id[1]) | ||
|
|
||
| ############################################################################### | ||
| # or by its index | ||
| element_0 = mesh.elements[0] | ||
| print(element_0) | ||
|
|
||
| ############################################################################### | ||
| # Query information about one particular element | ||
| # ---------------------------------------------- | ||
| # You can request the IDs of the nodes attached to an ``Element`` object | ||
| print(element_0.node_ids) | ||
|
|
||
| # or the list of ``Node`` objects | ||
| print(element_0.nodes) | ||
|
|
||
| # To get the number of nodes attached, use | ||
| print(element_0.num_nodes) | ||
|
|
||
| # Get the type of the element | ||
| print(element_0.type_info) | ||
| print(element_0.type) | ||
|
|
||
| # Get the shape of the element | ||
| print(element_0.shape) | ||
|
|
||
| ############################################################################### | ||
| # Element types and materials | ||
| # --------------------------- | ||
| # The ``Mesh`` object provides access to properties defined on all elements, | ||
| # such as their types or their associated materials. | ||
|
|
||
| # Get the type of all elements | ||
| print(mesh.element_types) | ||
|
|
||
| # Get the materials of all elements | ||
| print(mesh.materials) | ||
|
|
||
| ############################################################################### | ||
| # Elemental connectivity | ||
| # ---------------------- | ||
| # The elemental connectivity maps elements to connected nodes, either using IDs or indexes. | ||
|
|
||
| # To access the indexes of the connected nodes using an element's index, use | ||
| element_to_node_connectivity = mesh.element_to_node_connectivity | ||
| print(element_to_node_connectivity[0]) | ||
|
|
||
| # To access the IDs of the connected nodes using an element's index, use | ||
| element_to_node_ids_connectivity = mesh.element_to_node_ids_connectivity | ||
| print(element_to_node_ids_connectivity[0]) | ||
|
|
||
| ############################################################################### | ||
| # Each connectivity object has a ``by_id`` property which changes the input from index to ID, thus: | ||
| # To access the indexes of the connected nodes using an element's ID, use | ||
| element_to_node_connectivity_by_id = mesh.element_to_node_connectivity.by_id | ||
| print(element_to_node_connectivity_by_id[3487]) | ||
|
|
||
| # To access the IDs of the connected nodes using an element's ID, use | ||
| element_to_node_ids_connectivity_by_id = mesh.element_to_node_ids_connectivity.by_id | ||
| print(element_to_node_ids_connectivity_by_id[3487]) | ||
|
|
||
| ############################################################################### | ||
| # Nodes | ||
| # ----- | ||
|
|
||
| # Get a node by its ID | ||
| node_1 = mesh.nodes.by_id[1] | ||
| print(node_1) | ||
|
|
||
| ############################################################################### | ||
| # Get a node by its index | ||
| print(mesh.nodes[0]) | ||
|
|
||
| ############################################################################### | ||
| # Get the coordinates of all nodes | ||
| print(mesh.coordinates) | ||
|
|
||
| ############################################################################### | ||
| # Query information about one particular node | ||
| # ------------------------------------------- | ||
| # Get the coordinates of a node | ||
| print(node_1.coordinates) | ||
|
|
||
| ############################################################################### | ||
| # Nodal connectivity | ||
| # ------------------ | ||
| # The nodal connectivity maps nodes to connected elements, either using IDs or indexes. | ||
|
|
||
| # To access the indexes of the connected elements using a node's index, use | ||
| node_to_element_connectivity = mesh.node_to_element_connectivity | ||
| print(node_to_element_connectivity[0]) | ||
|
|
||
| # To access the IDs of the connected elements using a node's index, use | ||
| node_to_element_ids_connectivity = mesh.node_to_element_ids_connectivity | ||
| print(node_to_element_ids_connectivity[0]) | ||
|
|
||
| ############################################################################### | ||
| # Each connectivity object has a ``by_id`` property which changes the input from index to ID, thus: | ||
| # To access the indexes of the connected elements using a node's ID, use | ||
| node_to_element_connectivity_by_id = mesh.node_to_element_connectivity.by_id | ||
| print(node_to_element_connectivity_by_id[1]) | ||
|
|
||
| # To access the IDs of the connected elements using a node's ID, use | ||
| node_to_element_ids_connectivity_by_id = mesh.node_to_element_ids_connectivity.by_id | ||
| print(node_to_element_ids_connectivity_by_id[1]) | ||
|
|
||
| ############################################################################### | ||
| # Splitting into meshes | ||
| # --------------------- | ||
| # You can split the global mesh according to mesh properties to work on specific parts of the mesh | ||
| meshes = simulation.split_mesh_by_properties( | ||
| properties=[elemental_properties.material, elemental_properties.element_shape] | ||
| ) | ||
| # The object obtained is a ``Meshes`` | ||
| print(meshes) | ||
|
|
||
| # Plotting a ``Meshes`` object plots a combination of all the ``Mesh`` objects within | ||
| meshes.plot(text="Mesh split") | ||
|
|
||
| ############################################################################### | ||
| # Select a specific ``Mesh`` in the ``Meshes``, by index | ||
| meshes[0].plot(text="First mesh in the split mesh") | ||
|
|
||
| ############################################################################### | ||
| # You can split the global mesh and select meshes based on specific property values | ||
| meshes_filtered = simulation.split_mesh_by_properties( | ||
| properties={ | ||
| elemental_properties.material: [2, 3, 4], | ||
| elemental_properties.element_shape: 1, | ||
| } | ||
| ) | ||
| meshes_filtered.plot(text="Mesh split and filtered") | ||
|
|
||
| ############################################################################### | ||
| # or with a unique combination of property values | ||
| meshes[{"mat": 5, "elshape": 0}].plot(text="Mesh for mat=5 and elshape=0") | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| """Module containing wrapper class for the connectivities property fields.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from abc import ABC, abstractmethod | ||
| from enum import Enum | ||
| from typing import List | ||
|
|
||
| from ansys.dpf.core.property_field import PropertyField | ||
| from ansys.dpf.core.scoping import Scoping | ||
|
|
||
|
|
||
| class ReturnMode(Enum): | ||
| """Enum made for internal use, to dictate the behavior of _ConnectivityList.""" | ||
|
|
||
| IDS = 1 | ||
| IDX = 2 | ||
|
|
||
|
|
||
| class _ConnectivityList(ABC): | ||
| """Abstract class for ConnectivityList objects.""" | ||
|
|
||
| def __init__( | ||
| self, | ||
| field: PropertyField, | ||
| mode: ReturnMode, | ||
| scoping: Scoping, | ||
| ): | ||
| """Constructs a _ConnectivityList by wrapping the given PropertyField. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| field: | ||
| Field of connectivity. | ||
| mode: | ||
| Whether to return indexes or IDs. | ||
| scoping: | ||
| Element or node scoping to map returned indexes to IDs. | ||
| """ | ||
| self._field = field | ||
| if mode not in [ReturnMode.IDS, ReturnMode.IDX]: | ||
| raise ValueError("'mode' argument must be a valid ReturnMode value") | ||
| self._mode = mode | ||
| self._scoping = scoping | ||
| self._idx = 0 | ||
| self.local_scoping = None | ||
|
|
||
| def __next__(self) -> List[int]: | ||
| """Returns the next element in the list.""" | ||
| if self._idx >= len(self): | ||
| raise StopIteration | ||
| out = self.__getitem__(self._idx) | ||
| self._idx += 1 | ||
| return out | ||
|
|
||
| def __getitem__(self, idx: int) -> List[int]: | ||
| """Returns, for a given entity index, the connected indexes or IDs (see ReturnMode).""" | ||
| if self._mode == ReturnMode.IDS: | ||
| return self._get_ids_from_idx(idx) | ||
| elif self._mode == ReturnMode.IDX: | ||
| return self._get_idx_from_idx(idx) | ||
|
|
||
| def __len__(self) -> int: | ||
| """Returns the number of entities.""" | ||
| return self._field.scoping.size | ||
|
|
||
| def __repr__(self) -> str: | ||
| """Returns string representation of a _ConnectivityList object.""" | ||
| return f"{self.__class__.__name__}({self.__str__()}, __len__={self.__len__()})" | ||
|
|
||
| def _short_list(self) -> str: | ||
| _str = "[" | ||
| if self.__len__() > 3: | ||
| _fst = self._field.get_entity_data(0) | ||
| _lst = self._field.get_entity_data(self.__len__() - 1) | ||
| if self._mode == ReturnMode.IDS: | ||
| _fst = self._to_ids(_fst) | ||
| _lst = self._to_ids(_lst) | ||
| _str += f"{_fst}, ..., {_lst}" | ||
| else: | ||
| conn_list = [ | ||
| self._field.get_entity_data(idx) for idx in range(self.__len__()) | ||
| ] | ||
| if self._mode == ReturnMode.IDS: | ||
| conn_list = list(map(self._to_ids, conn_list)) | ||
| _str += ", ".join(map(str, conn_list)) | ||
| _str += "]" | ||
| return _str | ||
|
|
||
| def __str__(self) -> str: | ||
| """Returns string representation of a _ConnectivityList object.""" | ||
| return self._short_list() | ||
|
|
||
| def _get_ids_from_idx(self, idx: int) -> List[int]: | ||
| """Helper method to retrieve list of IDs from a given index.""" | ||
| return self._to_ids(self._get_idx_from_idx(idx)) | ||
|
|
||
| def _get_idx_from_idx(self, idx: int) -> List[int]: | ||
| """Helper method to retrieve list of indexes from a given index.""" | ||
| return self._field.get_entity_data(idx).tolist() | ||
|
|
||
| def _to_ids(self, indices) -> List[int]: | ||
| """Helper method to convert a list of indexes into a list of IDs.""" | ||
| if not self.local_scoping: | ||
| self.local_scoping = self._scoping.as_local_scoping() | ||
|
|
||
| to_id = self.local_scoping.id | ||
| return list(map(to_id, indices)) | ||
|
|
||
| @abstractmethod | ||
| def __iter__(self): # pragma: no cover | ||
| """Returns the object to iterate on.""" | ||
|
|
||
|
|
||
| class ConnectivityListByIndex(_ConnectivityList): | ||
| """Connectivity list object using indexes as input.""" | ||
|
|
||
| @property | ||
| def by_id(self) -> ConnectivityListById: | ||
| """Returns an equivalent list which accepts IDs as input.""" | ||
| return ConnectivityListById( | ||
| field=self._field, mode=self._mode, scoping=self._scoping | ||
| ) | ||
|
|
||
| def __iter__(self) -> ConnectivityListByIndex: | ||
| """Returns the object to iterate on.""" | ||
| self._idx = 0 | ||
| return self | ||
|
|
||
|
|
||
| class ConnectivityListById(_ConnectivityList): | ||
| """Connectivity list object using IDs as input.""" | ||
|
|
||
| def __getitem__(self, id: int) -> List[int]: # pylint: disable=redefined-builtin | ||
| """Returns, for a given entity ID, the connected indexes or IDs (see ReturnMode).""" | ||
| idx = self._field.scoping.index(id) | ||
| return super().__getitem__(idx) | ||
|
|
||
| def __iter__(self) -> ConnectivityListByIndex: | ||
| """Returns the object to iterate on.""" | ||
| return ConnectivityListByIndex( | ||
| field=self._field, | ||
| mode=self._mode, | ||
| scoping=self._scoping, | ||
| ) |
Uh oh!
There was an error while loading. Please reload this page.