Skip to content

feat: Get raw value for faces connectivity data. #4244

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

Merged
merged 18 commits into from
Jul 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 1 addition & 0 deletions doc/changelog.d/4244.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Get raw value for faces connectivity data.
48 changes: 37 additions & 11 deletions doc/source/user_guide/fields/field_data.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,20 +80,45 @@ in the ``data_types`` list.
# Example: The centroid of the 16th face has coordinates [-0.3463, 0.0, -0.0328].
array([-0.34634298, 0. , -0.03276413], dtype=float32)

To obtain face connectivity data, specify ``FacesConnectivity`` as the ``data_types`` parameter.
To obtain face connectivity data, specify ``FacesConnectivity`` in the ``data_types`` parameter
when constructing a ``SurfaceFieldDataRequest``. The returned data provides a flat, NumPy array
of vertex indices that describe how each face is connected to the mesh's vertices.

The data is stored in a compact "flattened" format. Each face is represented by a sequence of
vertex indices, preceded by an integer specifying how many vertices the face contains. This means
the array is structured as:

::

[N₀, V₀₁, V₀₂, ..., V₀ₙ₀, N₁, V₁₁, V₁₂, ..., V₁ₙ₁, ...]

Where:
- ``Nᵢ`` is the number of vertices in the *i*-th face,
- ``Vᵢⱼ`` are the vertex indices that make up that face.

This format is compact and well-suited for custom post-processing, visualization, or exporting mesh
data to third-party tools. It supports arbitrary polygonal faces, including triangles, quads, and
NGons (with more than 4 vertices).

.. code-block:: python

>>> faces_connectivity_request = SurfaceFieldDataRequest(
>>> surfaces=[VelocityInlet(settings_source=solver_session, name="inlet")],
>>> data_types=[SurfaceDataType.FacesConnectivity]
>>> data_types=[SurfaceDataType.FacesConnectivity],
>>> flatten_connectivity=True,
>>> )
>>> faces_connectivity_data = field_data.get_field_data(faces_connectivity_request)

# FacesConnectivity provides indices of vertices for each face. For example:
# Face 6 is connected to vertices 4, 5, 12, and 11.
>>> faces_connectivity_data["inlet"].connectivity[5]
array([ 4, 5, 12, 11])
>>> faces_connectivity_data["inlet"].connectivity
array([ 4, 3, 2, 1, 0, 3, 10, 11, 12, ...], dtype=int32)

In this example, the first face has 4 vertices (a quad), connected to vertices [3, 2, 1, 0]. The second
face has 3 vertices (a triangle), connected to [10, 11, 12], and so on.

.. note::

This format is consistent with VTK-style unstructured mesh representations (for example, as used in pyvista).


Get scalar field data
~~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -138,6 +163,7 @@ To obtain pathlines field data, use ``PathlinesFieldDataRequest``:
>>> velocity_pathlines_request = PathlinesFieldDataRequest(
>>> field_name="x-velocity",
>>> surfaces=[VelocityInlet(settings_source=solver_session, name="inlet")]
>>> flatten_connectivity=True,
>>> )
>>> velocity_path_lines_data = field_data.get_field_data(velocity_pathlines_request)

Expand All @@ -146,13 +172,13 @@ To obtain pathlines field data, use ``PathlinesFieldDataRequest``:
# Velocity shape: (29565,) - Scalar velocity values at each pathline point.
>>> velocity_path_lines_data["inlet"].vertices.shape
(29565, 3)
>>> len(velocity_path_lines_data["inlet"].lines)
29303
>>> velocity_path_lines_data["inlet"].lines.shape
(87909,)
>>> velocity_path_lines_data["inlet"].scalar_field.shape
(29565,)
>>> velocity_path_lines_data["inlet"].lines[100]
# Example: Pathline 101 connects vertices 100 and 101.
array([100, 101])
>>> velocity_path_lines_data["inlet"].lines[:6]
# Example: First line connects vertices 0 and 1. Following line connects vertices 1 and 2, and so on.
array([2, 0, 1, 2, 1, 2], dtype=int32)

Making multiple requests in a single transaction
------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion doc/source/user_guide/fields/solution_data.rst
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ Set solution variable data
~~~~~~~~~~~~~~~~~~~~~~~~~~
You can set solution variable data for a given ``domain_name`` by calling the ``set_data``
method and passing required ``variable_name`` and dictionary of ``zone_name``
to numpy array of ``solution_variable_data``
to NumPy array of ``solution_variable_data``

Additionally solution_variable_data object also supports ``create_empty_array`` method. This method can be used to
generate ``numpy zeros array`` for a given ``domain_name``, ``zone_name`` and
Expand Down
8 changes: 6 additions & 2 deletions doc/source/user_guide/offline/file_session.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,23 @@ Single-phase
>>> vertices_and_faces_connectivity_request = SurfaceFieldDataRequest(
>>> data_types=[SurfaceDataType.Vertices, SurfaceDataType.FacesConnectivity],
>>> surfaces=[3, 4],
>>> flatten_connectivity=True,
>>> )
>>> solution_variable_temperature_request = ScalarFieldDataRequest(field_name="SV_T", surfaces=[3, 4], node_value=False, boundary_value=False)
>>> velocity_request = VectorFieldDataRequest(field_name="velocity", surfaces=[3, 4])
>>> transaction.add_requests(vertices_and_faces_connectivity_request, solution_variable_temperature_request, velocity_request)
>>> data = transaction.get_response()
>>> data.get_field_data(vertices_and_faces_connectivity_request)[3][SurfaceDataType.Vertices]
>>> data.get_field_data(vertices_and_faces_connectivity_request)[3].vertices
array([[ 0. , -0.1016 , 0. ],
[-0.00635 , -0.1016 , 0. ],
[-0.00634829, -0.10203364, 0.00662349],
...,
[ 0.01857703, -0.19223897, 0.03035362],
[ 0.0124151 , -0.19273971, 0.03034735],
[ 0.00620755, -0.19304685, 0.03033731]])
[ 0.00620755, -0.19304685, 0.03033731]], shape=(3810, 3))
>>> data.get_field_data(vertices_and_faces_connectivity_request)[4].connectivity
array([ 4, 295, 294, ..., 265, 1482, 2183],
shape=(10090,), dtype=uint32)
>>> data.get_field_data(solution_variable_temperature_request)[4]
array([293.14999, 293.14999, 293.14999, ..., 293.14999, 293.14999,
293.14999])
Expand Down
4 changes: 3 additions & 1 deletion doc/styles/config/vocabularies/ANSYS/accept.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ metaclasses
monitor
MonitorsManager
numpy
NumPy
PODMAN
Podman
poppler
Expand Down Expand Up @@ -82,4 +83,5 @@ venv
create_workflow
load_workflow
codegen
discoverability
discoverability
NGons
95 changes: 75 additions & 20 deletions src/ansys/fluent/core/field_data_interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,16 @@
# SOFTWARE.

"""Common interfaces for field data."""

from abc import ABC, abstractmethod
from enum import Enum
from typing import Callable, Dict, List, NamedTuple
import warnings

import numpy as np
import numpy.typing as npt

from ansys.fluent.core.exceptions import DisallowedValuesError
from ansys.fluent.core.pyfluent_warnings import PyFluentDeprecationWarning
from ansys.fluent.core.variable_strategies import (
FluentFieldDataNamingStrategy as naming_strategy,
)
Expand All @@ -52,6 +53,7 @@ class SurfaceFieldDataRequest(NamedTuple):
data_types: List[SurfaceDataType] | List[str]
surfaces: List[int | str | object]
overset_mesh: bool | None = False
flatten_connectivity: bool = False


class ScalarFieldDataRequest(NamedTuple):
Expand Down Expand Up @@ -87,6 +89,7 @@ class PathlinesFieldDataRequest(NamedTuple):
coarsen: int | None = 1
velocity_domain: str | None = "all-phases"
zones: list | None = None
flatten_connectivity: bool = False


class BaseFieldInfo(ABC):
Expand Down Expand Up @@ -482,16 +485,6 @@ def __init__(self, pathlines_data_for_surface):

class _ReturnFieldData:

@staticmethod
def _get_faces_connectivity_data(data):
faces_data = []
i = 0
while i < len(data):
end = i + 1 + data[i]
faces_data.append(data[i + 1 : end])
i = end
return faces_data

@staticmethod
def _scalar_data(
field_name: str,
Expand All @@ -512,20 +505,32 @@ def _surface_data(
surface_ids: List[int],
surface_data: np.array | List[np.array],
deprecated_flag: bool | None = False,
flatten_connectivity: bool = False,
) -> Dict[int | str, Dict[SurfaceDataType, np.array | List[np.array]]]:
surfaces = get_surfaces_from_objects(surfaces)
ret_surf_data = {}
for count, surface in enumerate(surfaces):
ret_surf_data[surface] = {}
for data_type in data_types:
if data_type == SurfaceDataType.FacesConnectivity:
ret_surf_data[surface][data_type] = (
_ReturnFieldData._get_faces_connectivity_data(
surface_data[surface_ids[count]][
SurfaceDataType.FacesConnectivity.value
]
if flatten_connectivity:
ret_surf_data[surface][data_type] = surface_data[
surface_ids[count]
][SurfaceDataType.FacesConnectivity.value]
else:
warnings.warn(
"Structured face connectivity output is deprecated and will be replaced by the flat format "
"in a future release. In the current release, pass 'flatten_connectivity=True' argument while creating the "
"'SurfaceFieldDataRequest' to request data in the flat format.",
PyFluentDeprecationWarning,
)
ret_surf_data[surface][data_type] = (
_transform_faces_connectivity_data(
surface_data[surface_ids[count]][
SurfaceDataType.FacesConnectivity.value
]
)
)
)
else:
ret_surf_data[surface][data_type] = surface_data[
surface_ids[count]
Expand Down Expand Up @@ -554,17 +559,28 @@ def _pathlines_data(
surface_ids: List[int],
pathlines_data: Dict,
deprecated_flag: bool | None = False,
flatten_connectivity: bool = False,
) -> Dict:
surfaces = get_surfaces_from_objects(surfaces)
path_lines_dict = {}
for count, surface in enumerate(surfaces):
if flatten_connectivity:
lines_data = pathlines_data[surface_ids[count]]["lines"]
else:
warnings.warn(
"Structured face connectivity output is deprecated and will be replaced by the flat format "
"in a future release. In the current release, pass 'flatten_connectivity=True' argument while creating the "
"'SurfaceFieldDataRequest' to request data in the flat format.",
PyFluentDeprecationWarning,
)
lines_data = _transform_faces_connectivity_data(
pathlines_data[surface_ids[count]]["lines"]
)
temp_dict = {
"vertices": pathlines_data[surface_ids[count]]["vertices"].reshape(
-1, 3
),
"lines": _ReturnFieldData._get_faces_connectivity_data(
pathlines_data[surface_ids[count]]["lines"]
),
"lines": lines_data,
field_name: pathlines_data[surface_ids[count]][field_name],
"pathlines-count": pathlines_data[surface_ids[count]][
"pathlines-count"
Expand Down Expand Up @@ -607,3 +623,42 @@ def get_surfaces_from_objects(surfaces: List[int | str | object]):
else:
updated_surfaces.append(surface)
return updated_surfaces


def _transform_faces_connectivity_data(data):
"""
Transform flat face connectivity data into structured face-wise format.

Each face in the flat array is represented by:
[N, v0, v1, ..., vN], where:
- N is the number of vertices in the face
- v0...vN are the vertex indices

This function parses such a flat array and returns a list of vertex index arrays,
each representing a face.

Parameters
----------
data : array-like of int
Flat array containing face connectivity data, typically returned from
`faces_connectivity_data["inlet"].connectivity`.

Returns
-------
faces_data : list of ndarray
List of 1D NumPy arrays, where each array contains the vertex indices
of a face.

Examples
--------
>>> flat_data = np.array([4, 4, 5, 12, 11, 3, 1, 2, 3], dtype=np.int32)
>>> _transform_faces_connectivity_data(flat_data)
[array([ 4, 5, 12, 11]), array([1, 2, 3])]
"""
faces_data = []
i = 0
while i < len(data):
end = i + 1 + data[i]
faces_data.append(data[i + 1 : end])
i = end
return faces_data
41 changes: 26 additions & 15 deletions src/ansys/fluent/core/file_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
_AllowedScalarFieldNames,
_AllowedSurfaceNames,
_ReturnFieldData,
_transform_faces_connectivity_data,
)
from ansys.fluent.core.filereader.case_file import CaseFile
from ansys.fluent.core.filereader.data_file import (
Expand Down Expand Up @@ -133,6 +134,7 @@ def _get_surface_data(
kwargs.get("surfaces"),
self.get_surface_ids(kwargs.get("surfaces")),
surface_data,
flatten_connectivity=kwargs.get("flatten_connectivity"),
)

def _get_vector_field_data(
Expand Down Expand Up @@ -650,6 +652,7 @@ def get_surface_data(
data_types: List[SurfaceDataType] | List[str],
surfaces: List[int | str],
overset_mesh: bool | None = False,
flatten_connectivity: bool = False,
):
"""Get surface data (vertices and faces connectivity).

Expand All @@ -661,6 +664,8 @@ def get_surface_data(
List of surface IDS or surface names for the surface data.
overset_mesh : bool, optional
Whether to provide the overset method. The default is ``False``.
flatten_connectivity: bool, optional
Whether to provide faces connectivity data in flattened format.

Returns
-------
Expand All @@ -673,13 +678,15 @@ def get_surface_data(
data_types=data_types,
surfaces=surfaces,
overset_mesh=overset_mesh,
flatten_connectivity=flatten_connectivity,
)

def _get_surface_data(
self,
data_types: List[SurfaceDataType] | List[str],
surfaces: List[int | str],
overset_mesh: bool | None = False,
flatten_connectivity: bool = False,
):
for d_type in data_types:
if isinstance(d_type, str):
Expand All @@ -697,24 +704,28 @@ def _get_surface_data(
}

if SurfaceDataType.FacesConnectivity in data_types:
return {
surface: self._get_faces_connectivity_data(
self._file_session._case_file.get_mesh().get_connectivity(
if flatten_connectivity:
return {
surface: self._file_session._case_file.get_mesh().get_connectivity(
surface_ids[count]
)
for count, surface in enumerate(surfaces)
}
else:
warnings.warn(
"Structured face connectivity output is deprecated and will be replaced by the flat format "
"in a future release. In the current release, pass 'flatten_connectivity=True' argument while creating the "
"'SurfaceFieldDataRequest' to request data in the flat format.",
PyFluentDeprecationWarning,
)
for count, surface in enumerate(surfaces)
}

@staticmethod
def _get_faces_connectivity_data(data):
faces_data = []
i = 0
while i < len(data):
end = i + 1 + data[i]
faces_data.append(data[i + 1 : end])
i = end
return faces_data
return {
surface: _transform_faces_connectivity_data(
self._file_session._case_file.get_mesh().get_connectivity(
surface_ids[count]
)
)
for count, surface in enumerate(surfaces)
}

@all_deprecators(
deprecate_arg_mappings=[
Expand Down
Loading