Skip to content
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

Mesh splitting and selection #346

Merged
merged 106 commits into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from 100 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
203 changes: 203 additions & 0 deletions examples/01-Detailed-Examples/05-mesh-exploration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
"""
.. _ref_mesh_exploration_example:

Explore the mesh
================
In this script a static simulation is used as an example to show how to
query mesh information such as connectivity, element IDs, element types and so on.
"""

###############################################################################
ansys-akarcher marked this conversation as resolved.
Show resolved Hide resolved
# 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

###############################################################################
# Get ``Simulation`` object
# -------------------------
# Get the ``Simulation`` object that allows access to the result. 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_all_kinds_of_complexity()
simulation = post.StaticMechanicalSimulation(example_path)

# print the simulation to get an overview of what's available
print(simulation)

###############################################################################
# Get the mesh
# ------------

# Retrieve the actual mesh
mesh = simulation.mesh

###############################################################################
# Query basic information about the mesh
# --------------------------------------

# Node IDs
n_ids = mesh.node_ids

# Element IDs
e_ids = mesh.element_ids

# Available named selection names
named_selections = mesh.named_selections.keys()

# Number of nodes
n_nodes = mesh.num_nodes

# Number of elements
n_elements = mesh.num_elements

# Number of named selections
n_ns = len(named_selections)

# Unit (get and set)
mesh_unit = mesh.unit
mesh.unit = "mm"

print(n_ids)
print(e_ids)
print(named_selections)
print(n_nodes)
print(n_elements)

###############################################################################
# Get Named Selections
# --------------------
ns_list = mesh.named_selections.keys()
first_key = ns_list[0]
named_selection = mesh.named_selections[first_key]

for k in mesh.named_selections.keys():
print(k)
for v in mesh.named_selections.values():
print(v)
for k, v in mesh.named_selections.items():
print(f"{k} = {v}")

###############################################################################
# Get elements
# ------------

# Get an element by ID
el_by_id = mesh.elements.by_id[1]
ansys-akarcher marked this conversation as resolved.
Show resolved Hide resolved

# Get an element by index
index = el_by_id.index
print(mesh.elements[index])

###############################################################################
# Element Types and Materials
# ---------------------------

# Get the element types
el_types = mesh.element_types
print(el_types)

# Get the materials
e_materials = mesh.materials
print(e_materials)

###############################################################################
# Query information about one particular element
# ----------------------------------------------

# Get the nodes of an element
elem_0_nodes = mesh.elements[0].nodes

# Get the node IDs of an element
elem_0_nodes_ids = mesh.elements[0].node_ids

# Get the number of nodes of an element
num_nodes_elem_0 = mesh.elements[0].num_nodes

# Get the type of the element
elem_0_type_info = mesh.elements[0].type_info
elem_0_type = mesh.elements[0].type

# Get the shape of the element
elem_0_shape = mesh.elements[0].shape

###############################################################################
# Get the elemental connectivity
# ------------------------------

# get node indices from element index
conn1 = mesh.element_to_node_connectivity

# get node IDs from element index
conn2 = mesh.element_to_node_ids_connectivity

el_idx_5 = mesh.elements[5]
# get node IDS from element ID
node_ids = conn2.by_id[el_idx_5.id]

###############################################################################
# Get nodes
# ---------

# Get a node by ID
node_by_id = mesh.nodes.by_id[1]

# Get a node by index
node_by_index = mesh.nodes[0]

# Get the coordinates of all nodes
print(mesh.coordinates)

###############################################################################
# Query information about one particular node
# -------------------------------------------

# Coordinates
node_1 = mesh.nodes[1].coordinates

# Get Nodal connectivity
conn3 = mesh.node_to_element_connectivity
conn4 = mesh.node_to_element_ids_connectivity

print(mesh.nodes[0])

# elements indices to elem_id
print(conn3[0])

# elements IDs from node index
print(conn4[0])

###############################################################################
# Splitting into meshes
# ---------------------

# Plot the mesh
mesh.plot()

# Split the global mesh according to mesh properties
meshes = simulation.split_mesh_by_properties(
properties=[elemental_properties.material, elemental_properties.element_shape]
)
meshes.plot()

# Split the global mesh and select meshes for specific property values
print(meshes)
meshes = simulation.split_mesh_by_properties(
properties={
elemental_properties.material: 1,
elemental_properties.element_shape: [0, 1],
}
)

meshes.plot()

# Select a specific Mesh in the Meshes, by index
meshes[0].plot()
# or by property values
meshes[{"mat": 1, "elshape": 0}].plot()
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.

Arguments:
Copy link
Contributor

Choose a reason for hiding this comment

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

Parameters ?

Suggested change
Arguments:
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