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

Expose streamlines #480

Merged
merged 14 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from 7 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
2 changes: 1 addition & 1 deletion src/ansys/dpf/post/examples/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Examples
--------
This module module exposes PyDPF-Core functionalities.
This package exposes PyDPF-Core functionalities.

See `here <https://dpf.docs.pyansys.com/dev/api/ansys.dpf.core.examples.html>`_
for a description of the PyDPF-Core ``example`` API.
Expand Down
2 changes: 1 addition & 1 deletion src/ansys/dpf/post/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,7 @@ def _build_selection(
node_ids: Union[List[int], None] = None,
location: Union[locations, str] = locations.nodal,
external_layer: bool = False,
skin: Union[bool] = False,
skin: Union[bool, List[int]] = False,
expand_cyclic: Union[bool, List[Union[int, List[int]]]] = True,
) -> Selection:
tot = (
Expand Down
6 changes: 6 additions & 0 deletions src/ansys/dpf/post/tools/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""Tools package.

Tools
-----
This package regroups helpers for different common post-treatment functionalities.
"""
78 changes: 78 additions & 0 deletions src/ansys/dpf/post/tools/streamlines.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
"""Module containing the helpers for streamlines.

Streamlines
-----------

"""
from typing import List, Union

from ansys.dpf.core.helpers import streamlines as core_streamlines
from ansys.dpf.core.plotter import DpfPlotter

from ansys.dpf import post


def plot_streamlines(
dataframe: post.DataFrame,
sources: List[dict],
streamline_thickness: Union[float, List[float]] = 0.01,
plot_mesh: bool = True,
mesh_opacity: float = 0.3,
plot_contour: bool = True,
contour_opacity: float = 0.3,
**kwargs,
):
"""Plot streamlines based on a vector field DataFrame.

Parameters
----------
dataframe:
A `post.DataFrame` object containing a vector field.
sources:
A list of dictionaries defining spherical point sources for the streamlines.
Expected keywords are "center", "radius", "max_time" and "n_points".
Keyword "max_time" is for the maximum integration pseudo-time for the streamline
computation algorithm, which defines the final length of the lines.
More information is available at :func:`pyvista.DataSetFilters.streamlines`.
streamline_thickness:
Thickness of the streamlines plotted. Use a list to specify a value for each source.
plot_contour:
Whether to plot the field's norm contour along with the streamlines.
contour_opacity:
Opacity to use for the field contour in case "plot_contour=True".
plot_mesh:
Whether to plot the mesh along the streamlines in case "plot_contour=False".
mesh_opacity:
Opacity to use for the mesh in case "plot_contour=False" and "plot_mesh=True".
**kwargs:

"""
# Select data to work with
meshed_region = dataframe._fc[0].meshed_region
field = dataframe._fc[0]

Check warning on line 52 in src/ansys/dpf/post/tools/streamlines.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/dpf/post/tools/streamlines.py#L51-L52

Added lines #L51 - L52 were not covered by tests
Copy link
Contributor

Choose a reason for hiding this comment

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

why the first field? what if you have a single time, but different label (like "elshape") in your data frame?

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 talked it out and it seems the only use-case is merging the fields labeled by zone, as well as selecting a set.
I updated the PR accordingly.


# Initialize the plotter
plt = DpfPlotter(**kwargs)

Check warning on line 55 in src/ansys/dpf/post/tools/streamlines.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/dpf/post/tools/streamlines.py#L55

Added line #L55 was not covered by tests

if plot_contour:
plt.add_field(field=field, opacity=contour_opacity)
elif plot_mesh:
plt.add_mesh(meshed_region=meshed_region, opacity=mesh_opacity)
if not isinstance(streamline_thickness, list):
streamline_thickness = [streamline_thickness] * len(sources)

Check warning on line 62 in src/ansys/dpf/post/tools/streamlines.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/dpf/post/tools/streamlines.py#L57-L62

Added lines #L57 - L62 were not covered by tests
# Add streamlines for each source
for i, source in enumerate(sources):
pv_streamline, pv_source = core_streamlines.compute_streamlines(

Check warning on line 65 in src/ansys/dpf/post/tools/streamlines.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/dpf/post/tools/streamlines.py#L64-L65

Added lines #L64 - L65 were not covered by tests
meshed_region=meshed_region,
field=field,
return_source=True,
source_radius=source["radius"],
source_center=source["center"],
n_points=source["n_points"] if "n_points" in source else 100,
max_time=source["max_time"] if "max_time" in source else None,
)
plt.add_streamlines(

Check warning on line 74 in src/ansys/dpf/post/tools/streamlines.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/dpf/post/tools/streamlines.py#L74

Added line #L74 was not covered by tests
pv_streamline, source=pv_source, radius=streamline_thickness[i]
)

plt.show_figure(**kwargs)

Check warning on line 78 in src/ansys/dpf/post/tools/streamlines.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/dpf/post/tools/streamlines.py#L78

Added line #L78 was not covered by tests
45 changes: 45 additions & 0 deletions tests/test_streamlines.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from conftest import SERVERS_VERSION_GREATER_THAN_OR_EQUAL_TO_7_0
import pytest

from ansys.dpf import post
from ansys.dpf.post import examples
from ansys.dpf.post.tools import streamlines


@pytest.mark.skipif(
not SERVERS_VERSION_GREATER_THAN_OR_EQUAL_TO_7_0,
reason="Fluid capabilities added with ansys-dpf-server 2024.1.pre0.",
)
class TestStreamlines:
@pytest.fixture
def simulation(self) -> post.FluidSimulation:
files_cfx = examples.download_cfx_heating_coil()
return post.FluidSimulation(cas=files_cfx["cas"], dat=files_cfx["dat"]) # noqa

def test_plot_streamlines(self, simulation):
import pyvista as pv

pv.OFF_SCREEN = False
dataframe = simulation.velocity(times=[0.0], zone_ids=[5])
print(dataframe)
sources = [
{"radius": 0.25, "center": (0.75, 0.0, 0.0), "n_points": 20},
{
"radius": 0.25,
"center": (0.0, 0.75, 0.0),
"n_points": 5,
"max_time": 10.0,
},
{"radius": 0.25, "center": (-0.75, 0.0, 0.0), "max_time": 2.0},
{"radius": 0.25, "center": (0.0, -0.75, 0.0)},
]
streamlines.plot_streamlines(
dataframe=dataframe,
sources=sources,
streamline_thickness=0.007,
plot_mesh=True,
mesh_opacity=0.2,
plot_contour=True,
contour_opacity=0.3,
title="Streamlines with multiple sources",
)
Loading