Skip to content
Merged
Show file tree
Hide file tree
Changes from 105 commits
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
bbf18e7
Add 05-mesh-exploration.py
PProfizi Mar 14, 2023
6995be2
Comments on API
PProfizi Mar 14, 2023
0bc4c45
Meeting 20/03
PProfizi Mar 20, 2023
d3add0e
Should expose MeshSelectionManager?
PProfizi Mar 21, 2023
d135076
Typo
PProfizi Mar 21, 2023
dfb6983
Add meshes.py
PProfizi Mar 21, 2023
87195ea
Add Meshes.select()
PProfizi Mar 21, 2023
0fe0cdd
Simulation.split_mesh_by_properties() - version using scopings
PProfizi Mar 21, 2023
b7eb6c8
WIP
PProfizi Mar 22, 2023
f575069
Add Mesh.plot()
PProfizi Mar 23, 2023
3b0edf0
Add Meshes.plot()
PProfizi Mar 23, 2023
d1ccfad
Add Meshes.__get_item__ by dictionary of {property: value}
PProfizi Mar 23, 2023
500d711
Working POC with split by properties, and selection by properties, wi…
PProfizi Mar 23, 2023
72accfc
Split mesh by list of properties
PProfizi Mar 23, 2023
94d9df0
Add test_meshes.py
PProfizi Mar 27, 2023
1396828
Use "import ansys.dpf.core as dpf" in test_mesh.py
PProfizi Mar 27, 2023
955ef07
Add test_simulation_split_mesh_by_properties
PProfizi Mar 27, 2023
ce7fa1e
Add Mesh and Meshes imports at module init
PProfizi Mar 27, 2023
e746560
Add Meshes.__len__()
PProfizi Mar 27, 2023
5fac5d7
Fix and test Meshes.select()
PProfizi Mar 27, 2023
2caad5b
Add selection by values in Simulation.split_mesh_by_properties()
PProfizi Mar 27, 2023
07e37fd
Update 05-mesh-exploration.py
PProfizi Mar 27, 2023
5f254b7
Inherit elemental_properties from core
PProfizi Mar 28, 2023
85957ab
Expose elemental_properties at post level
PProfizi Mar 28, 2023
37814c6
Simulation.split_by_property allow dict of properties and values, imp…
PProfizi Mar 28, 2023
f0a516d
Update test_simulation_split_by_properties accordingly
PProfizi Mar 28, 2023
50745c6
Remove expose elemental_properties at post level due to circular imports
PProfizi Mar 28, 2023
8eb03ab
Fix Simulation.split_mesh_by_properties docstring
PProfizi Mar 28, 2023
9ecfcc5
Add Meshes.plot docstring example
PProfizi Mar 28, 2023
e55da83
Add Meshes docstring examples
PProfizi Mar 28, 2023
3f26763
Update test_meshes.py
PProfizi Mar 28, 2023
2415afe
Add Mesh.coordinates and Mesh.plot docstring example
PProfizi Mar 28, 2023
c732e38
Update draft example with new requirements for the Mesh API
PProfizi Mar 28, 2023
a610f61
Fix Meshes docstrings
PProfizi Mar 29, 2023
23d9989
Completed mesh basic information querying section
ansys-akarcher Mar 30, 2023
913188c
Added Elements, Nodes accessors, moved NamedSelection
ansys-akarcher Mar 31, 2023
1fd41aa
NamedSelection: composition over inheritance
ansys-akarcher Apr 6, 2023
217777e
Added mock PropertyFieldsContainer for DataFrame, updated Elements
ansys-akarcher Apr 6, 2023
f107ab5
updated Nodes list, added materials property
ansys-akarcher Apr 6, 2023
56f1c5d
split Element.type into id & info
ansys-akarcher Apr 6, 2023
d8e8414
Added Simple ConnectivityList
ansys-akarcher Apr 13, 2023
7b64975
Added element types getter
ansys-akarcher Apr 13, 2023
ccec46b
Completed doc and pre-commit checks
ansys-akarcher Apr 17, 2023
6dca2f8
Updated mesh example
ansys-akarcher Apr 18, 2023
befe782
minor changes
ansys-akarcher Apr 18, 2023
5d56699
Apply suggestions from code review
ansys-akarcher Apr 24, 2023
4eba411
Implemented suggestions
ansys-akarcher Apr 25, 2023
e81da71
Added mesh related tests
ansys-akarcher Apr 25, 2023
c9f07a2
pre-commit checks conformance
ansys-akarcher Apr 25, 2023
0bde530
Added string repr, ElementType composition, Node wrapper
ansys-akarcher Apr 26, 2023
30f8186
Fixed string rep, added docstrings
ansys-akarcher Apr 26, 2023
4a38217
Fixed server variable in mock class PropertyFieldFC
ansys-akarcher Apr 26, 2023
a1fd26c
Added minimal functionality for df.select on PropertyFields
ansys-akarcher Apr 27, 2023
97e13fe
fixed mistake
ansys-akarcher Apr 27, 2023
15325e1
Merge branch 'master' into feat/mesh_api
ansys-akarcher Apr 27, 2023
a9316a3
Added skin getter method
ansys-akarcher May 2, 2023
19a4452
Renamed connectivity getters, updated tests
ansys-akarcher May 2, 2023
354cd08
Revert "Added skin getter method"
ansys-akarcher May 15, 2023
76507ba
Make PropertyFieldsContainer private
ansys-akarcher May 15, 2023
29daf4a
Merge branch 'master' into feat/mesh_api
ansys-akarcher Jun 19, 2023
c627349
Merge master
PProfizi Jul 7, 2023
d5e0630
Fix styling
PProfizi Jul 7, 2023
474fbf3
Update test ref
PProfizi Jul 7, 2023
c0e9e04
Remove warning
PProfizi Jul 7, 2023
026cee4
Fix code quality
PProfizi Jul 7, 2023
b2611c8
Fix code quality
PProfizi Jul 7, 2023
cfacf69
Fix code quality
PProfizi Jul 7, 2023
b7ec61d
Add test_connectivity.py/test_connectivity_connectivity_list_idx
PProfizi Jul 10, 2023
80bd4b6
Fix calls to ConnectivityListIdx and ConnectivityListIds
PProfizi Jul 10, 2023
44e00ad
Fix Mesh.element_to_node_ids_connectivity, Mesh.node_to_element_ids_c…
PProfizi Jul 10, 2023
8d26130
Fix connectivity.py/ConnectivityListById init
PProfizi Jul 10, 2023
22f92cf
Fix code quality in 05-mesh-exploration.py
PProfizi Jul 10, 2023
a925508
WIP
PProfizi Jul 10, 2023
4438389
Refactor
PProfizi Jul 10, 2023
3e17d35
Improve coverage connectivity.py
PProfizi Jul 10, 2023
9d19ab6
Improve coverage connectivity.py
PProfizi Jul 10, 2023
0f22b79
Improve coverage mesh.py
PProfizi Jul 10, 2023
91ba3aa
Improve coverage mesh.py
PProfizi Jul 10, 2023
c09459b
Fix code quality
PProfizi Jul 10, 2023
f628c3f
Fix 221 retro
PProfizi Jul 11, 2023
9c6a732
Improve coverage test_connectivity.py
PProfizi Jul 11, 2023
7b2dc6d
Coverage elements.py/ElementType
PProfizi Jul 11, 2023
98a070b
Coverage elements.py/Element
PProfizi Jul 11, 2023
110efbe
Refactor and coverage of elements.py
PProfizi Jul 11, 2023
2b6b351
Coverage mesh.py
PProfizi Jul 11, 2023
8725827
Coverage selection.py
PProfizi Jul 11, 2023
9ba9345
Refactor NamedSelections in named_selection.py
PProfizi Jul 11, 2023
8e5ff1a
Refactor NamedSelections in named_selection.py
PProfizi Jul 11, 2023
d207d37
Add test_named_selection.py
PProfizi Jul 11, 2023
7fd3e0e
Add test_named_selection.py
PProfizi Jul 11, 2023
baeef13
Update CI to work with 241 dev libraries
PProfizi Jul 12, 2023
a6aebe9
Make test_named_selection.py retro-compatible
PProfizi Jul 13, 2023
775433d
Refactor nodes.py
PProfizi Jul 13, 2023
3dab0c5
Coverage nodes.py
PProfizi Jul 13, 2023
f4dd528
Merge branch 'master' into feat/mesh_api
PProfizi Jul 13, 2023
d0bffb3
Move PropertyFieldsContainer to core
PProfizi Jul 17, 2023
747b889
Remove rogue prints from tests
PProfizi Jul 17, 2023
7536af0
Finalize move of PropertyFieldsContainer to ansys-dpf-core
PProfizi Jul 18, 2023
a4bf121
Merge branch 'master' into feat/mesh_api
PProfizi Jul 18, 2023
9b215bf
Add examples to docstrings
PProfizi Jul 18, 2023
83e35af
Take remarks into account
PProfizi Jul 18, 2023
7ea1b89
Merge branch 'master' into feat/mesh_api
PProfizi Jul 18, 2023
c3ae713
Merge branch 'master' into feat/mesh_api
PProfizi Jul 20, 2023
7d132e7
Throw when trying to instantiate a post.Mesh with a None as MeshedRegion
PProfizi Jul 20, 2023
19f2149
Working 05-mesh-exploration.py
PProfizi Jul 20, 2023
3e271a4
Improve notebook formatting of 05-mesh-exploration.py
PProfizi Jul 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 222 additions & 0 deletions examples/01-Detailed-Examples/05-mesh-exploration.py
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
Copy link
Contributor

Choose a reason for hiding this comment

The 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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI @PProfizi

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cbellot000 yes, I just added examples in dosctrings of post.Mesh
Will be updating the example to make a proper one

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")
2 changes: 2 additions & 0 deletions src/ansys/dpf/post/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
from ansys.dpf.post.harmonic_mechanical_simulation import ( # noqa: F401
HarmonicMechanicalSimulation,
)
from ansys.dpf.post.mesh import Mesh # noqa: F401
from ansys.dpf.post.meshes import Meshes # noqa: F401
from ansys.dpf.post.misc import Report
from ansys.dpf.post.modal_mechanical_simulation import ( # noqa: F401
ModalMechanicalSimulation,
Expand Down
3 changes: 3 additions & 0 deletions src/ansys/dpf/post/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
------

"""
from ansys.dpf.core.common import ( # noqa: F401 # pylint: disable=W0611
elemental_properties,
)

from ansys.dpf.post.fluid_simulation import FluidSimulation
from ansys.dpf.post.harmonic_mechanical_simulation import HarmonicMechanicalSimulation
Expand Down
145 changes: 145 additions & 0 deletions src/ansys/dpf/post/connectivity.py
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,
)
Loading