Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 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
80 changes: 80 additions & 0 deletions examples/06-plotting/08-plot_scopings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Copyright (C) 2020 - 2025 ANSYS, Inc. and/or its affiliates.
# SPDX-License-Identifier: MIT
#
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

"""
.. _plotting_scopings:

Review of available plotting commands
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This example show how to plot scopings with a mesh location.

"""

from ansys.dpf import core as dpf
from ansys.dpf.core import examples

# Plot the bare mesh of a model
model = dpf.Model(examples.download_cfx_mixing_elbow())

mesh = model.metadata.meshed_region

node_scoping_1 = dpf.Scoping(location=dpf.locations.nodal, ids=mesh.nodes.scoping.ids[0:100])
node_scoping_2 = dpf.Scoping(location=dpf.locations.nodal, ids=mesh.nodes.scoping.ids[300:400])

node_sc = dpf.ScopingsContainer()
node_sc.add_label(label="scoping", default_value=1)
node_sc.add_scoping(label_space={"scoping": 1}, scoping=node_scoping_1)
node_sc.add_scoping(label_space={"scoping": 2}, scoping=node_scoping_2)

# node_sc.plot(mesh=mesh, show_mesh=True)
# exit()
# node_scoping.plot(mesh=mesh, color="red")

element_scoping_1 = dpf.Scoping(
location=dpf.locations.elemental, ids=mesh.elements.scoping.ids[0:100]
)
element_scoping_2 = dpf.Scoping(
location=dpf.locations.elemental, ids=mesh.elements.scoping.ids[300:400]
)
element_sc = dpf.ScopingsContainer()
element_sc.add_label(label="scoping", default_value=1)
element_sc.add_scoping(label_space={"scoping": 1}, scoping=element_scoping_1)
element_sc.add_scoping(label_space={"scoping": 2}, scoping=element_scoping_2)

element_sc.plot(mesh=mesh, show_mesh=True)
# element_scoping.plot(mesh=mesh, color="green")


# from ansys.dpf.core.plotter import DpfPlotter
#
# plt = DpfPlotter()
# plt.add_scoping(node_scoping, mesh, show_mesh=True, color="red")
# plt.add_scoping(element_scoping, mesh, color="green")
# plt.show_figure()
#
# faces_scoping = dpf.Scoping(
# location=dpf.locations.faces,
# ids=mesh.faces.scoping.ids[0:100]
# )
#
# faces_scoping.plot(mesh=mesh, color="orange")
6 changes: 5 additions & 1 deletion src/ansys/dpf/core/elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from __future__ import annotations

from enum import Enum
from typing import TYPE_CHECKING

import numpy as np

Expand All @@ -34,6 +35,9 @@
from ansys.dpf.core.element_descriptor import ElementDescriptor
from ansys.dpf.gate import integral_types

if TYPE_CHECKING: # pragma: no cover
from ansys.dpf.core.scoping import Scoping


class Element:
"""
Expand Down Expand Up @@ -492,7 +496,7 @@ def __get_element(self, elementindex=None, elementid=None):
return Element(self._mesh, elementid, elementindex, nodesOut)

@property
def scoping(self) -> scoping.Scoping:
def scoping(self) -> Scoping:
"""
Scoping of the elements.

Expand Down
6 changes: 4 additions & 2 deletions src/ansys/dpf/core/meshes_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
Contains classes associated with the DPF MeshesContainer.
"""

from __future__ import annotations

from ansys.dpf.core import errors as dpf_errors, meshed_region
from ansys.dpf.core.collection_base import CollectionBase
from ansys.dpf.core.plotter import DpfPlotter
Expand Down Expand Up @@ -159,14 +161,14 @@ def get_meshes(self, label_space):
"""
return super()._get_entries(label_space)

def get_mesh(self, label_space_or_index):
def get_mesh(self, label_space_or_index: int | dict[str, int]):
"""Retrieve the mesh at a requested index or label space.

Raises an exception if the request returns more than one mesh.

Parameters
----------
label_space_or_index : dict[str,int] , int
label_space_or_index:
Scoping of the requested mesh, such as ``{"time": 1, "complex": 0}``
or the index of the mesh.

Expand Down
11 changes: 9 additions & 2 deletions src/ansys/dpf/core/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,18 @@

"""Nodes."""

from __future__ import annotations

from typing import TYPE_CHECKING

import numpy as np

from ansys.dpf.core.check_version import version_requires
from ansys.dpf.core.common import locations, nodal_properties

if TYPE_CHECKING: # pragma: no cover
from ansys.dpf.core.scoping import Scoping


class Node:
"""
Expand Down Expand Up @@ -194,13 +201,13 @@ def __get_node(self, nodeindex=None, nodeid=None):
return Node(self._mesh, nodeid, nodeindex, node_coordinates)

@property
def scoping(self):
def scoping(self) -> Scoping:
"""
Scoping of the nodes.

Returns
-------
scoping : Scoping
scoping:
Scoping of the nodes.

Examples
Expand Down
82 changes: 81 additions & 1 deletion src/ansys/dpf/core/plotter.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@

from __future__ import annotations

import os
from pathlib import Path
import sys
import tempfile
Expand All @@ -48,6 +47,7 @@

if TYPE_CHECKING: # pragma: no cover
from ansys.dpf.core import Operator, Result
from ansys.dpf.core.field import Field
from ansys.dpf.core.fields_container import FieldsContainer
from ansys.dpf.core.meshed_region import MeshedRegion

Expand Down Expand Up @@ -233,6 +233,37 @@ def get_label_at_grid_point(index):
)
return label_actors

def add_scoping(
self,
scoping: dpf.core.Scoping,
mesh: dpf.core.MeshedRegion,
show_mesh: bool = False,
**kwargs,
):
# Add the mesh to the scene with low opacity
if show_mesh:
self._plotter.add_mesh(mesh=mesh.grid, opacity=0.3)

scoping_mesh = None

# If the scoping is nodal, use the add_points_label method
if scoping.location == locations.nodal:
node_indexes = np.where(np.isin(mesh.nodes.scoping.ids, scoping.ids))[0]
# grid_points = [mesh.grid.points[node_index] for node_index in node_indexes]
scoping_mesh = mesh.grid.extract_points(ind=node_indexes, include_cells=False)
# If the scoping is elemental, extract their edges and use active scalars to color them
if scoping.location == locations.elemental:
element_indexes = np.where(np.isin(mesh.elements.scoping.ids, scoping.ids))[0]
scoping_mesh = mesh.grid.extract_cells(ind=element_indexes)

# If the scoping is faces, extract their edges and use active scalars to color them
if scoping.location == locations.faces:
raise NotImplementedError("Cannot plot a face scoping.")

# Filter kwargs
kwargs_in = _sort_supported_kwargs(bound_method=self._plotter.add_mesh, **kwargs)
self._plotter.add_mesh(mesh=scoping_mesh, **kwargs_in)

def add_field(
self,
field,
Expand Down Expand Up @@ -688,6 +719,55 @@ def add_field(
**kwargs,
)

def add_scoping(
self,
scoping: dpf.core.Scoping,
mesh: dpf.core.MeshedRegion,
show_mesh: bool = False,
**kwargs,
):
"""Add a scoping to the plotter.

A mesh is required to translate the scoping into entities to plot.
Tou can plot the mesh along with the scoping entities using ``show_mesh``.

Parameters
----------
scoping:
Scoping with a mesh-based location and IDs of entities to plot.
mesh:
``MeshedRegion`` to plot the field on.
show_mesh:
Whether to show the mesh along with the scoping entities.
**kwargs : optional
Additional keyword arguments for the plotter. More information
are available at :func:`pyvista.plot`.

Examples
--------
>>> from ansys.dpf import core as dpf
>>> from ansys.dpf.core import examples
>>> model = dpf.Model(examples.download_cfx_mixing_elbow())
>>> mesh = model.metadata.meshed_region
>>> node_scoping = dpf.Scoping(
... location=dpf.locations.nodal,
... ids=mesh.nodes.scoping.ids[0:100]
...)
>>> element_scoping = dpf.Scoping(
... location=dpf.locations.elemental,
... ids=mesh.elements.scoping.ids[0:100]
...)
>>> from ansys.dpf.core.plotter import DpfPlotter
>>> plt = DpfPlotter()
>>> plt.add_scoping(node_scoping, mesh, show_mesh=True, color="red")
>>> plt.add_scoping(element_scoping, mesh, color="green")
>>> plt.show_figure()

"""
self._internal_plotter.add_scoping(
scoping=scoping, mesh=mesh, show_mesh=show_mesh, **kwargs
)

def show_figure(self, **kwargs):
"""Plot the figure built by the plotter object.

Expand Down
42 changes: 42 additions & 0 deletions src/ansys/dpf/core/scoping.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,48 @@ def as_local_scoping(self):
""" # noqa: E501
return _LocalScoping(self)

def plot(self, mesh, show_mesh: bool = False, **kwargs):
"""Plot the entities of the mesh corresponding to the scoping.

Parameters
----------
mesh:
Mesh to use to translate the scoping into mesh entities.
show_mesh:
Whether to also show the mesh with low opacity.
**kwargs : optional
Additional keyword arguments for the plotter. More information
are available at :func:`pyvista.plot`.

Returns
-------
(cpos, image):
Returns what the pyvista.show() method returns based on arguments.

Examples
--------
>>> from ansys.dpf import core as dpf
>>> from ansys.dpf.core import examples
>>> model = dpf.Model(examples.download_cfx_mixing_elbow())
>>> mesh = model.metadata.meshed_region
>>> node_scoping = dpf.Scoping(
... location=dpf.locations.nodal,
... ids=mesh.nodes.scoping.ids[0:100]
...)
>>> node_scoping.plot(mesh=mesh, color="red")
>>> element_scoping = dpf.Scoping(
... location=dpf.locations.elemental,
... ids=mesh.elements.scoping.ids[0:100]
...)
>>> element_scoping.plot(mesh=mesh, color="green")

"""
from ansys.dpf.core.plotter import DpfPlotter

plt = DpfPlotter(**kwargs)
plt.add_scoping(scoping=self, mesh=mesh, show_mesh=show_mesh, **kwargs)
return plt.show_figure(**kwargs)


class _LocalScoping(Scoping):
"""Caches the internal data of the scoping so that it can be modified locally.
Expand Down
Loading
Loading