Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
66 changes: 39 additions & 27 deletions src/ansys/dpf/core/mesh_scoping_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,87 +23,99 @@
"""
mesh_scoping_factory.

Contains functions to simplify creating mesh scopings.
Contains functions to simplify creating a mesh scoping.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING: # pragma: nocover
from ansys.dpf.core.server_types import AnyServerType
from ansys.dpf.core.scoping import IdVectorType
from ansys.dpf.core.model import Model

from ansys.dpf.core import Scoping
from ansys.dpf.core.common import locations


def nodal_scoping(node_ids, server=None):
"""Create a specific nodal :class:`ansys.dpf.core.Scoping` associated with a mesh.
def nodal_scoping(node_ids: IdVectorType, server: AnyServerType = None) -> Scoping:
"""Create a nodal :class:`ansys.dpf.core.Scoping` defining a list of node IDs.

Parameters
----------
node_ids : list[int]
List of IDs for the nodes.
server : DpfServer, optional
node_ids:
List of node IDs.
server:
Server with the channel connected to the remote or local instance.
The default is ``None``, in which case an attempt is made to use the
global server.

Returns
-------
scoping : Scoping
scoping:
A nodal scoping containing the node IDs provided.
"""
scoping = Scoping(server=server, ids=node_ids, location=locations.nodal)
return scoping


def elemental_scoping(element_ids, server=None):
"""Create a specific elemental :class:`ansys.dpf.core.Scoping` associated with a mesh.
def elemental_scoping(element_ids: IdVectorType, server: AnyServerType = None) -> Scoping:
"""Create an elemental :class:`ansys.dpf.core.Scoping` defining a list of element IDs.

Parameters
----------
element_ids : list[int]
List of IDs for the elements.
server : DpfServer, optional
element_ids:
List of element IDs.
server:
Server with the channel connected to the remote or local instance.
The default is ``None``, in which case an attempt is made to use the
global server.

Returns
-------
scoping : Scoping
scoping:
An elemental scoping containing the element IDs provided.
"""
scoping = Scoping(server=server, ids=element_ids, location=locations.elemental)
return scoping


def face_scoping(face_ids, server=None):
"""Create a specific face :class:`ansys.dpf.core.Scoping` associated with a mesh.
def face_scoping(face_ids: IdVectorType, server: AnyServerType = None) -> Scoping:
"""Create a face :class:`ansys.dpf.core.Scoping`defining a list of face IDs.

Parameters
----------
face_ids : list[int]
List of IDs for the faces.
server : DpfServer, optional
face_ids:
List of face IDs.
server:
Server with the channel connected to the remote or local instance.
The default is ``None``, in which case an attempt is made to use the
global server.

Returns
-------
scoping : Scoping
scoping:
A face scoping containing the face IDs provided.
"""
scoping = Scoping(server=server, ids=face_ids, location=locations.faces)
return scoping


def named_selection_scoping(named_selection_name, model, server=None):
"""Create a specific :class:`ansys.dpf.core.Scoping` associated with a specified model's mesh.
def named_selection_scoping(named_selection_name: str, model: Model) -> Scoping:
"""Create a :class:`ansys.dpf.core.Scoping` based on a named selection in a model.

Parameters
----------
named_selection_name : str
named_selection_name:
Name of the named selection.
server : DpfServer, optional
Server with the channel connected to the remote or local instance.
The default is ``None``, in which case an attempt is made to use the
global server.
model:
Model where the named selection exists.

Returns
-------
scoping : Scoping
scoping:
A scoping containing the IDs of the entities in the named selection.
The location depends on the type of entities targeted by the named selection.
"""
return model.metadata.named_selection(named_selection_name)
118 changes: 76 additions & 42 deletions src/ansys/dpf/core/scoping.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@

"""Scoping."""

from __future__ import annotations
import traceback
from typing import Union, TYPE_CHECKING
import warnings
import ctypes

Expand All @@ -44,39 +46,60 @@
dpf_array,
utils,
)
from ansys.dpf.gate.dpf_array import DPFArray

if TYPE_CHECKING: # pragma: nocover
from ansys.dpf.core.server_types import AnyServerType
import ansys.grpc.dpf.scoping_pb2.Scoping as ScopingMessage
from ctypes import c_void_p as ScopingPointer

IdVectorType = Union[list[int], range]


class Scoping:
"""Represents a scoping, which is a subset of a model support.

Parameters
----------
scoping : ctypes.c_void_p, ansys.grpc.dpf.scoping_pb2.Scoping message, optional

server : DPFServer, optional
scoping:
Grpc message or pointer for an existing Scoping on the server.
server:
Server with channel connected to the remote or local instance.
The default is ``None``, in which case an attempt is made to use the
global server.
ids:
List of entity IDs.
location:
Location for this scoping. Defines the type of entities the IDs correspond to.
For example, if location is :py:attr:`locations.nodal`,
then the scoping is a list of node IDs.

Examples
--------
Create a mesh scoping.
Create a scoping for mesh entities.

>>> from ansys.dpf import core as dpf
>>> # 1. using the mesh_scoping_factory
>>> from ansys.dpf.core import mesh_scoping_factory
>>> # a. scoping with elemental location that targets the elements with id 2, 7 and 11
>>> my_elemental_scoping = mesh_scoping_factory.elemental_scoping([2, 7, 11])
>>> # b. scoping with nodal location that targets the elements with id 4 and 6
>>> my_nodal_scoping = mesh_scoping_factory.nodal_scoping([4, 6])
>>> #2. using the classic API
>>> my_scoping = dpf.Scoping()
>>> my_scoping.location = dpf.locations.nodal #optional
>>> my_scoping.ids = list(range(1,11))
>>> # b. scoping with nodal location that targets the elements with id 4 to 6
>>> my_nodal_scoping = mesh_scoping_factory.nodal_scoping(range(4, 7))
>>> #2. using the Scoping class directly
>>> # a. scoping with elemental location that targets the elements with id 2, 7 and 11
>>> my_elemental_scoping = dpf.Scoping(location=dpf.locations.elemental, ids=[2, 7, 11])
>>> # b. scoping with nodal location that targets the elements with id 4 to 6
>>> my_nodal_scoping = dpf.Scoping(ids=range(4, 7))

"""

def __init__(self, scoping=None, server=None, ids=None, location=None):
def __init__(
self,
scoping: Union[ScopingMessage, ScopingPointer] = None,
server: AnyServerType = None,
ids: IdVectorType = None,
location: locations = None,
):
"""Initialize the scoping with an optional scoping message or by connecting to a stub."""
# step 1: get server
self._server = server_module.get_or_create_server(
Expand Down Expand Up @@ -116,6 +139,8 @@ def __init__(self, scoping=None, server=None, ids=None, location=None):

# step5: handle specific calls to set attributes
if ids is not None:
if isinstance(ids, range):
ids = list(ids)
self.ids = ids
if location is not None:
self.location = location
Expand Down Expand Up @@ -152,18 +177,20 @@ def _set_location(self, loc=locations.nodal):
self._api.scoping_set_location(self, loc)

@version_requires("2.1")
def _set_ids(self, ids):
def _set_ids(self, ids: IdVectorType):
"""Set the ids.

Parameters
----------
ids : list of int
IDs to set.
ids:
Entity IDs to set.

Notes
-----
Print a progress bar.
Prints a progress bar. # TODO: still true?
"""
if isinstance(ids, range):
ids = list(ids)
if isinstance(self._server, server_types.InProcessServer):
self._api.scoping_resize(self, len(ids))
ids_ptr = self._api.scoping_get_ids(self, len(ids))
Expand Down Expand Up @@ -209,15 +236,15 @@ def _get_ids(self, np_array=None):
except NotImplementedError:
return self._api.scoping_get_ids(self, np_array)

def set_id(self, index, scopingid):
"""Set the ID of a scoping's index.
def set_id(self, index: int, scopingid: int):
"""Set the ID of the entity at index in the scoping.

Parameters
----------
index : int
Index of the scoping.
scopingid : int
ID of the scoping.
index:
Index in the scoping.
scopingid:
ID of the entity.
"""
self._api.scoping_set_entity(self, scopingid, index)

Expand Down Expand Up @@ -251,73 +278,79 @@ def _get_index(self, scopingid):
"""
return self._api.scoping_index_by_id(self, scopingid)

def id(self, index: int):
"""Retrieve the ID at a given index.
def id(self, index: int) -> int:
"""Retrieve the entity ID at a given index.

Parameters
----------
index : int
Index for the ID.
index:
Index of the entity in the scoping.

Returns
-------
size : int
entity_id:
ID of the entity at index in the scoping.

"""
return self._get_id(index)

def index(self, id: int):
"""Retrieve the index of a given ID.
def index(self, id: int) -> int:
"""Retrieve the index for a given entity ID.

Parameters
----------
id : int
ID for the index to retrieve.
id:
Entity ID at the index in the scoping.

Returns
-------
size : int
index:
Index in the scoping for the entity ID.

"""
return self._get_index(id)

@property
def ids(self):
def ids(self) -> Union[DPFArray, list[int]]:
"""Retrieve a list of IDs in the scoping.

Returns
-------
ids : DPFArray, list of int
List of IDs to retrieve. By default a mutable DPFArray is returned, to change
the return type to a list for the complete python session, see
List of IDs to retrieve. By default, a mutable DPFArray is returned.
To change the return type to a list for the complete python session, see
:func:`ansys.dpf.core.settings.get_runtime_client_config` and
:func:`ansys.dpf.core.runtime_config.RuntimeClientConfig.return_arrays`.
To change the return type to a list once, use
:func:`ansys.dpf.core.scoping.Scoping._get_ids` with the parameter ``np_array=False``.

Notes
-----
Print a progress bar.
Prints a progress bar. # TODO is that true?
"""
return self._get_ids()

@ids.setter
def ids(self, value):
def ids(self, value: IdVectorType):
self._set_ids(value)

@property
def location(self):
"""Location of the IDs as a string, such as ``"nodal"``, ``"elemental"``, and ``"time_freq"``.
def location(self) -> str:
"""Location of the scoping as a string.

This defines the type of entity the IDs stored correspond to.

Returns
-------
location : str
location:
The location of the scoping.
One of the values of :class:`~ansys.dpf.core.common.locations`.

"""
return self._get_location()

@location.setter
def location(self, value):
def location(self, value: locations):
self._set_location(value)

def __len__(self):
Expand Down Expand Up @@ -362,12 +395,13 @@ def __setitem__(self, index, id):
return self.set_id(index, id)

@property
def size(self):
def size(self) -> int:
"""Length of the list of IDs.

Returns
-------
size : int
size:
Size if the scoping.

"""
return self._count()
Expand Down
2 changes: 2 additions & 0 deletions src/ansys/dpf/core/server_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -1496,3 +1496,5 @@ def __del__(self):
# DpfServer: TypeAlias = LegacyGrpcServer
# Python <3.10
DpfServer = LegacyGrpcServer

AnyServerType = Union[LegacyGrpcServer, InProcessServer, GrpcServer]
Loading