Skip to content

MeshedRegion.plot() with PropertyField #1526

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

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
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
4 changes: 2 additions & 2 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@


# enable off_screen plotting to avoid test interruption
core.settings.disable_off_screen_rendering()
core.settings.bypass_pv_opengl_osmesa_crash()
# core.settings.disable_off_screen_rendering()
# core.settings.bypass_pv_opengl_osmesa_crash()


class DPFDocTestRunner(DocTestRunner):
Expand Down
76 changes: 45 additions & 31 deletions src/ansys/dpf/core/meshed_region.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@
MeshedRegion
============
"""
from __future__ import annotations
import traceback
import warnings
from typing import Union, List, TYPE_CHECKING

import ansys.dpf.core
import ansys.dpf.core.errors

from ansys.dpf.core import scoping, field, property_field
from ansys.dpf.core import scoping, field, fields_container
from ansys.dpf.core.property_field import PropertyField
if TYPE_CHECKING:
from ansys.dpf.core.results import Result
from ansys.dpf.core.dpf_operator import Operator
from ansys.dpf.core.check_version import server_meet_version, version_requires
from ansys.dpf.core.common import (
locations,
Expand Down Expand Up @@ -291,28 +298,29 @@ def available_property_fields(self):
)
return available_property_fields

def property_field(self, property_name):
def property_field(self, property_name: str) -> Union[field.Field, PropertyField]:
"""
Property field getter. It can be coordinates (field),
element types (property field)...

Returns
-------
field_or_property_field : core.Field or core.PropertyField
field_or_property_field:
Field or PropertyField.
"""
return self.field_of_properties(property_name)

@version_requires("3.0")
def set_property_field(self, property_name, value):
def set_property_field(self, property_name: str, value: Union[field.Field, PropertyField]):
"""
Property field setter. It can be coordinates (field),
element types (property field)...

Parameters
----------
property_name : str
property_name:
property name of the field to set
value : PropertyField or Field
value:
"""
if property_name is nodal_properties.coordinates:
self.set_coordinates_field(value)
Expand All @@ -321,24 +329,24 @@ def set_property_field(self, property_name, value):

@update_grid
@version_requires("3.0")
def set_coordinates_field(self, coordinates_field):
def set_coordinates_field(self, coordinates_field: field.Field):
"""
Coordinates field setter.

Parameters
----------
coordinates_field : PropertyField or Field
coordinates_field:
"""
self._api.meshed_region_set_coordinates_field(self, coordinates_field)

@property
def available_named_selections(self):
def available_named_selections(self) -> List[str]:
"""
List of available named selections.

Returns
-------
named_selections : list str
named_selections:
"""
return self._get_available_named_selections()

Expand All @@ -356,18 +364,19 @@ def _get_available_named_selections(self):
named_selections.append(self._api.meshed_region_get_named_selection_name(self, index))
return named_selections

def named_selection(self, named_selection):
def named_selection(self, named_selection: str) -> scoping.Scoping:
"""
Scoping containing the list of nodes or elements in the named selection.

Parameters
----------
named_selection : str
named_selection:
Name of the named selection.

Returns
-------
named_selection : Scoping
named_selection:
Scoping equivalent to the named selection.
"""
if server_meet_version("2.1", self._server):
out = self._api.meshed_region_get_named_selection_scoping(self, named_selection)
Expand All @@ -388,15 +397,16 @@ def named_selection(self, named_selection):
)

@version_requires("3.0")
def set_named_selection_scoping(self, named_selection_name, scoping):
def set_named_selection_scoping(self, named_selection_name: str, scoping: scoping.Scoping):
"""
Named selection scoping setter.

Parameters
----------
named_selection_name : str
named selection name
scoping : Scoping
named_selection_name:
Name of the named selection.
scoping:
Scoping to associate to the named selection.
"""
return self._api.meshed_region_set_named_selection_scoping(
self, named_selection_name, scoping
Expand Down Expand Up @@ -529,27 +539,29 @@ def grid(self):

def plot(
self,
field_or_fields_container=None,
field_or_fields_container: Union[
field.Field, PropertyField, fields_container.FieldsContainer, None
] = None,
shell_layers=None,
deform_by=None,
scale_factor=1.0,
deform_by: Union[field.Field, Result, Operator, None] = None,
scale_factor: float = 1.0,
**kwargs,
):
"""
Plot the field or fields container on the mesh.
Plot the mesh, bare or with data.

Parameters
----------
field_or_fields_container : dpf.core.Field or dpf.core.FieldsContainer
Field or fields container to plot. The default is ``None``.
shell_layers : core.shell_layers, optional
field_or_fields_container:
Field, PropertyField, or FieldsContainer to plot on the mesh.
shell_layers: core.shell_layers, optional
Enum used to set the shell layers if the model to plot contains shell elements.
deform_by : Field, Result, Operator, optional
deform_by: Field, Result, Operator, optional
Used to deform the plotted mesh. Must output a 3D vector field.
Defaults to None.
scale_factor : float, optional
Scaling factor to apply when warping the mesh. Defaults to 1.0.
**kwargs : optional
scale_factor:
Scaling factor to apply when warping the mesh.
**kwargs: optional
Additional keyword arguments for the plotter. For additional keyword
arguments, see ``help(pyvista.plot)``.

Expand All @@ -565,7 +577,7 @@ def plot(
>>> model.metadata.meshed_region.plot(field)

"""
if field_or_fields_container is not None:
if isinstance(field_or_fields_container, (field.Field, fields_container.FieldsContainer)):
pl = Plotter(self, **kwargs)
return pl.plot_contour(
field_or_fields_container,
Expand All @@ -585,6 +597,8 @@ def plot(
show_axes=kwargs.pop("show_axes", True),
**kwargs,
)
if isinstance(field_or_fields_container, PropertyField):
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if isinstance(field_or_fields_container, PropertyField):
elif isinstance(field_or_fields_container, PropertyField):

pl.add_field(field=field_or_fields_container, meshed_region=self, **kwargs)
kwargs.pop("notebook", None)
return pl.show_figure(**kwargs)

Expand Down Expand Up @@ -670,11 +684,11 @@ def field_of_properties(self, property_name):
else:
field_out = self._api.meshed_region_get_property_field(self, property_name)
if isinstance(field_out, int):
res = property_field.PropertyField(server=self._server, property_field=field_out)
res = PropertyField(server=self._server, property_field=field_out)
return res
else:
if field_out.datatype == "int":
return property_field.PropertyField(
return PropertyField(
server=self._server, property_field=field_out
)
else:
Expand Down
29 changes: 23 additions & 6 deletions src/ansys/dpf/core/plotter.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,11 +216,28 @@ def add_field(
**kwargs,
):
# Get the field name
name = field.name.split("_")[0]
unit = field.unit
kwargs.setdefault("stitle", f"{name} ({unit})")

kwargs = self._set_scalar_bar_title(kwargs)
if isinstance(field, dpf.core.Field):
name = field.name.split("_")[0]
categories = False
unit = field.unit
kwargs.setdefault("stitle", f"{name} ({unit})")
kwargs = self._set_scalar_bar_title(kwargs)
elif isinstance(field, dpf.core.PropertyField):
try:
name = field.name
except dpf_errors.DpfVersionNotSupported:
name = ""
categories = True
kwargs.setdefault("scalar_bar_args", {
"title": name,
"n_labels": 0,
})
# from itertools import cycle
# cycler = cycle(['Reds', 'Greens', 'Blues', 'Greys', 'Oranges', 'Purples'])
kwargs.setdefault("cmap", "tab20")
values = set(field.data)
kwargs.setdefault("clim", [min(values)-0.5, max(values)+0.5])
kwargs.setdefault("annotations", dict([(v, str(int(v))) for v in values]))

kwargs.setdefault("show_edges", True)
kwargs.setdefault("nan_color", "grey")
Expand Down Expand Up @@ -277,7 +294,7 @@ def add_field(
meshed_region.deform_by(deform_by, scale_factor), as_linear
)
grid.set_active_scalars(None)
self._plotter.add_mesh(grid, scalars=overall_data, **kwargs_in)
self._plotter.add_mesh(grid, scalars=overall_data, categories=categories, **kwargs_in)

# If deformed geometry, print the scale_factor
if deform_by and scale_factor_legend is not False:
Expand Down
53 changes: 53 additions & 0 deletions src/ansys/dpf/core/property_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@
PropertyField
=============
"""
from __future__ import annotations

import numpy as np
from typing import Union, TYPE_CHECKING
if TYPE_CHECKING:
from ansys.dpf.core.results import Result
from ansys.dpf.core.field import Field
from ansys.dpf.core.dpf_operator import Operator
from ansys.dpf.core.meshed_region import MeshedRegion
from ansys.dpf.core.check_version import version_requires
from ansys.dpf.core.common import natures, locations, _get_size_of_list
from ansys.dpf.core import scoping, dimensionality
Expand All @@ -17,6 +24,7 @@
dpf_array,
dpf_vector,
)
from ansys.dpf.core.plotter import DpfPlotter


class PropertyField(_FieldBase):
Expand Down Expand Up @@ -342,6 +350,51 @@ def name(self, value):
self._field_definition, name=value
)

def plot(
self,
meshed_region: MeshedRegion,
deform_by: Union[Field, Result, Operator, None] = None,
scale_factor: float = 1.0,
**kwargs,
):
"""Plot the PropertyField on a MeshedRegion.

Parameters
----------
meshed_region:
The mesh to plot the property field onto.
deform_by: Field, Result, Operator, optional
Used to deform the plotted mesh. Must output a 3D vector field.
Defaults to None.
scale_factor:
Scaling factor to apply when warping the mesh.
**kwargs: optional
Additional keyword arguments for the plotter. For additional keyword
arguments, see ``help(pyvista.plot)``.

Examples
--------
Plot the displacement field from an example file.

>>> import ansys.dpf.core as dpf
>>> from ansys.dpf.core import examples
>>> model = dpf.Model(examples.find_multishells_rst())
>>> mesh = model.metadata.meshed_region
>>> pf = mesh.property_field(property_name="mat")
>>> pf.plot(meshed_region=mesh)
"""
pl = DpfPlotter(**kwargs)
pl.add_field(
field=self,
meshed_region=meshed_region,
deform_by=deform_by,
scale_factor=scale_factor,
show_axes=kwargs.pop("show_axes", True),
**kwargs,
)
kwargs.pop("notebook", None)
return pl.show_figure(**kwargs)


class _LocalPropertyField(_LocalFieldBase, PropertyField):
"""Caches the internal data of a field so that it can be modified locally.
Expand Down
8 changes: 4 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@

ACCEPTABLE_FAILURE_RATE = 0

core.settings.disable_off_screen_rendering()
os.environ["PYVISTA_OFF_SCREEN"] = "true"
core.settings.bypass_pv_opengl_osmesa_crash()
os.environ["MPLBACKEND"] = "Agg"
# core.settings.disable_off_screen_rendering()
Copy link
Contributor

Choose a reason for hiding this comment

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

This needs to be reverted before merging, right?

# os.environ["PYVISTA_OFF_SCREEN"] = "true"
# core.settings.bypass_pv_opengl_osmesa_crash()
# os.environ["MPLBACKEND"] = "Agg"
# currently running dpf on docker. Used for testing on CI
DPF_SERVER_TYPE = os.environ.get("DPF_SERVER_TYPE", None)
running_docker = ansys.dpf.core.server_types.RUNNING_DOCKER.use_docker
Expand Down
16 changes: 16 additions & 0 deletions tests/test_plotter.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,22 @@ def test_mesh_field_plot(multishells):
mesh.plot(f)


@pytest.mark.skipif(not HAS_PYVISTA, reason="Please install pyvista")
def test_mesh_property_field_plot(multishells):
model = core.Model(multishells)
mesh = model.metadata.meshed_region
pf = mesh.property_field(property_name="mat")
mesh.plot(pf)


@pytest.mark.skipif(not HAS_PYVISTA, reason="Please install pyvista")
def test_property_field_plot(multishells):
model = core.Model(multishells)
mesh = model.metadata.meshed_region
pf = mesh.property_field(property_name="mat")
pf.plot(meshed_region=mesh)


@pytest.mark.skipif(not HAS_PYVISTA, reason="Please install pyvista")
def test_plotter_on_mesh(allkindofcomplexity):
model = Model(allkindofcomplexity)
Expand Down
Loading