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

Add fluid result averaging, FluidMeshInfo, and Faces #435

Merged
merged 43 commits into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
15fa5da
Raise for plot on empty Dataframe
PProfizi Jul 21, 2023
25ac22b
Add location argument to generic result requests
PProfizi Jul 21, 2023
c4a3a3a
Integrated results mass_flow_rate and surface_heat_rate are only avai…
PProfizi Jul 21, 2023
4864351
Mark integrated results
PProfizi Jul 21, 2023
db5e6ec
Fix and mark requests on cells as filtering-out face zone IDs
PProfizi Jul 21, 2023
f8584c8
Introduce the native_location dynamic argument
PProfizi Jul 21, 2023
47ce406
Add first averaging tests for fluid
PProfizi Jul 21, 2023
d3eb81f
Fix surface_heat_rate and surface_heat_rate_on_faces
PProfizi Jul 24, 2023
4eb1146
Add back enthalpy_on_faces
PProfizi Jul 24, 2023
2a972ec
Allow query of surface_heat_rate (on faces) using a list of cell IDs
PProfizi Jul 24, 2023
a222f4a
Add face methods in selection.py: select_faces, select_nodes_of_faces…
PProfizi Jul 24, 2023
d99e7fd
Update FluidSimulation._build_selection to correctly handle requests …
PProfizi Jul 24, 2023
a7c6035
Add Mesh.num_faces, Mesh.faces, Mesh.face_to_node_ids_connectivity, M…
PProfizi Jul 24, 2023
c262013
Add faces.py
PProfizi Jul 24, 2023
55b9bdc
Add Mesh.face_ids
PProfizi Jul 24, 2023
1926b86
Raise on dataframe.plot when empty mesh index
PProfizi Jul 24, 2023
7480605
Fix Selection.select_nodes_of_faces
PProfizi Jul 24, 2023
89bf70a
Only ask to filter cell zones on request with zones or qualifiers for…
PProfizi Jul 24, 2023
47f6774
Add test_mesh_faces
PProfizi Jul 24, 2023
e729957
Raise in FluidSimulation result APIs when result is not available (sh…
PProfizi Jul 24, 2023
8402461
Move mesh_info pproperty from Simulation to FluidSimulation
PProfizi Jul 25, 2023
2877d39
Commit new fluid tests for averaging and cross location requests
PProfizi Jul 25, 2023
ef1b6fe
Add MeshInfo, simplify 'zones' to cell_zones and face_zones dictionaries
PProfizi Jul 25, 2023
6b62ee9
Add MeshInfo.cell_zones_to_face_zones
PProfizi Jul 25, 2023
15d3b9d
Fix FluidSimulation._try_get_result_info
PProfizi Jul 25, 2023
1158676
Add filtering of zones for ElementalAndFaces and raise due to current…
PProfizi Jul 25, 2023
1db1a9c
Fix test_fluid_simulation_result_unavailable
PProfizi Jul 25, 2023
e7c5eff
Fix raise error when querying ElementalAndFaces results with a face_s…
PProfizi Jul 25, 2023
27f2d9d
Remove capability to ask for results on faces using cell_ids -> trans…
PProfizi Jul 25, 2023
adf6287
Update test_fluid_simulation.py with raise error on ElementalAndFaces…
PProfizi Jul 25, 2023
a356bce
Fix test since cell_ids not available for query on face results
PProfizi Jul 25, 2023
4fe9478
Fix Mesh docstrings
PProfizi Jul 25, 2023
76a63b2
Fix retro
PProfizi Jul 25, 2023
1dc7a69
Add coverage to faces.py
PProfizi Jul 26, 2023
46e6658
Improve coverage of mesh.py
PProfizi Jul 26, 2023
785d1d2
Improve coverage of mesh_info.py
PProfizi Jul 26, 2023
3e889f4
Improve coverage of selection.py
PProfizi Jul 26, 2023
2943594
Fix MeshInfo docstring
PProfizi Jul 26, 2023
ea7b6da
Update FluidMeshInfo docstring
PProfizi Jul 26, 2023
77c29c2
Update faces.py
PProfizi Jul 26, 2023
0dbf302
Fix MeshInfo docstring
PProfizi Jul 26, 2023
f76a819
Fix test_spatial_selection_select_named_selection
PProfizi Jul 26, 2023
4204663
Update test_fluid_simulation.py per comments
PProfizi Jul 26, 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
1 change: 0 additions & 1 deletion src/ansys/dpf/post/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
from ansys.dpf.post.transient_mechanical_simulation import ( # noqa: F401
TransientMechanicalSimulation,
)
from ansys.dpf.post.zone import Zone, Zones # noqa: F401

# this must be after some ansys.dpf.post import
__version__ = importlib_metadata.version("ansys-dpf-post")
Expand Down
4 changes: 4 additions & 0 deletions src/ansys/dpf/post/dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,8 @@ def plot(self, shell_layer=shell_layers.top, **kwargs) -> Union[DpfPlotter, None
The interactive plotter object used for plotting.

"""
if len(self.index.mesh_index) == 0:
raise ValueError("Cannot plot a Dataframe with an empty mesh index.")
label_space = {}
if kwargs != {}:
axis_kwargs, kwargs = self._filter_arguments(arguments=kwargs)
Expand Down Expand Up @@ -772,6 +774,8 @@ def plot(self, shell_layer=shell_layers.top, **kwargs) -> Union[DpfPlotter, None
fc = self._fc
label_space = fc.get_label_space(0)

if len(fc) == 0:
raise ValueError("No data to plot.")
for field in fc:
# Treat multi-layer field
shell_layer_check = field.shell_layers
Expand Down
158 changes: 158 additions & 0 deletions src/ansys/dpf/post/faces.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
"""This module contains Face and Faces classes."""

from __future__ import annotations

from abc import ABC, abstractmethod
from typing import List

from ansys.dpf.core import errors
from ansys.dpf.core import faces as core_faces
from ansys.dpf.core.nodes import Node

from ansys.dpf.post.elements import ElementType


class Face:
"""Proxy class wrapping dpf.core.faces.Face."""

def __init__(self, face: core_faces.Face):
"""Constructs a Proxy Face object."""
self._face = face

@property
def node_ids(self) -> List[int]:
"""See :py:meth:`ansys.dpf.core.faces.Face.node_ids`."""
return self._face.node_ids

@property
def id(self) -> int:
"""See :py:meth:`ansys.dpf.core.faces.Face.id`."""
return self._face.id

@property
def index(self) -> int:
"""See :py:meth:`ansys.dpf.core.faces.Face.index`."""
return self._face.index

@property
def nodes(self) -> List[Node]:
"""See :py:meth:`ansys.dpf.core.faces.Face.nodes`."""
return self._face.nodes

@property
def num_nodes(self) -> int:
"""See :py:meth:`ansys.dpf.core.faces.Face.n_nodes`."""
return self._face.n_nodes

@property
def type_info(self) -> ElementType:
"""Gets an element descriptor, See :py:meth:`ansys.dpf.core.faces.Face.id`."""
return ElementType(self._face.type.value)

@property
def type(self) -> core_elements.element_types:
"""Returns the Element Type."""
return self._face.type

@property
def to_node_connectivity(self) -> List[int]:
"""See :py:meth:`ansys.dpf.core.faces.Face.connectivity`."""
return self._face.connectivity

def __repr__(self) -> str:
"""Returns string representation of a Face."""
return f"Face(type={self.type},index={self.index},id={self.id})"

def __str__(self) -> str:
"""Returns string representation of a Face."""
return str(self._face)


class _FaceList(ABC):
"""Iterator class for the FaceList."""

def __init__(self, face_list: core_faces.Faces):
"""Constructs an Iterator from a face list."""
self._face_list = face_list
self._idx = 0

def __next__(self) -> Face:
"""Returns the next Face in the list."""
if self._idx >= len(self._face_list):
raise StopIteration
ret = self[self._idx]
self._idx += 1
return ret

def __getitem__(self, index: int) -> Face:
"""Returns a post.Face based on an index in the current list."""
return Face(self._face_list[index])

def __len__(self) -> int:
"""Returns the number of faces in the list."""
return self._face_list.n_faces

def __repr__(self) -> str:
"""Returns a string representation of _FaceList object."""
return f"{self.__class__.__name__}({self}, __len__={len(self)})"

def _short_list(self) -> str:
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure that name is appropriate regarding what the function does...

_str = "["
if self.__len__() > 3:
_fst = Face(self._face_list[0]).type_info.name
_lst = Face(self._face_list[len(self) - 1]).type_info.name
_str += f"{_fst}, ..., {_lst}"
else:
face_list = [Face(self._face_list[idx]) for idx in range(len(self))]
_str += ", ".join(map(lambda el: el.type_info.name, face_list))
_str += "]"
return _str

def __str__(self) -> str:
"""Returns a string representation of a _FaceList object."""
return self._short_list()

@abstractmethod
def __iter__(self): # pragma: no cover
"""Returns the object to iterate on."""
PProfizi marked this conversation as resolved.
Show resolved Hide resolved


class FaceListByIndex(_FaceList):
"""Face list object using indexes as input."""

@property
def by_id(self) -> FaceListById:
"""Returns an equivalent list which accepts IDs as input."""
return FaceListById(self._face_list)

def __iter__(self) -> FaceListByIndex:
"""Returns the object to iterate over."""
self._idx = 0
return self

def __contains__(self, face: Face) -> bool:
"""Checks if the given element in the list."""
return len(self) > face.index >= 0


class FaceListById(_FaceList):
"""Face list object using IDs as input."""

def __getitem__(self, id: int) -> Face: # pylint: disable=redefined-builtin
"""Access a Face with an ID."""
idx = self._face_list.scoping.index(id)
try:
return super().__getitem__(idx)
except errors.DPFServerException as e:
if "face not found" in str(e):
raise ValueError(f"Face with ID={id} not found in the list.")
else:
raise e # pragma: no cover

def __contains__(self, face: Face) -> bool:
"""Checks if the given face is in the list."""
return face.id in self._face_list.scoping.ids

def __iter__(self) -> FaceListByIndex:
"""Returns the object to iterate over."""
return FaceListByIndex(self._face_list)
Loading