Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
1d4aa8d
Add create named selection and get obejcts from named selections
gmalinve Jun 24, 2026
e70435e
chore: adding changelog file 7832.added.md [dependabot-skip]
pyansys-ci-bot Jun 24, 2026
ab68551
add tests to create and get objs in named selection
gmalinve Jun 24, 2026
bad335e
Merge branch 'main' into feat/create_get_named_selections
gmalinve Jun 24, 2026
205c3d4
Merge branch 'main' into feat/create_get_named_selections
gmalinve Jun 30, 2026
2af6278
Merge branch 'main' into feat/create_get_named_selections
gmalinve Jun 30, 2026
904fbe7
Merge branch 'main' into feat/create_get_named_selections
gmalinve Jul 1, 2026
d15e490
add new NamedSelection
gmalinve Jul 3, 2026
7523388
Merge branch 'main' into feat/create_get_named_selections
gmalinve Jul 3, 2026
942c08b
chore: adding changelog file 7832.added.md [dependabot-skip]
pyansys-ci-bot Jul 3, 2026
37f068f
update tests
gmalinve Jul 3, 2026
056c1a7
Add example docstrings
gmalinve Jul 3, 2026
3c3da60
Merge branch 'main' into feat/create_get_named_selections
gmalinve Jul 3, 2026
e7b1597
Add example docstrings
gmalinve Jul 3, 2026
7094dde
Merge branch 'main' into feat/create_get_named_selections
gmalinve Jul 6, 2026
e8f3b6d
Merge branch 'main' into feat/create_get_named_selections
gmalinve Jul 6, 2026
1ce50de
fix icepak tests
gmalinve Jul 6, 2026
de647ce
Merge branch 'main' into feat/create_get_named_selections
gmalinve Jul 7, 2026
b2052d7
remove try/except
gmalinve Jul 7, 2026
02ffc72
remove try/except
gmalinve Jul 7, 2026
9128a29
add AEDT version check
gmalinve Jul 8, 2026
ecf8824
pragma no cover
gmalinve Jul 8, 2026
664ed24
Merge branch 'main' into feat/create_get_named_selections
gmalinve Jul 20, 2026
06c412f
Merge branch 'main' into feat/create_get_named_selections
eblanco-ansys Jul 21, 2026
e481b48
Merge branch 'main' into feat/create_get_named_selections
gmalinve Jul 21, 2026
1d649a6
add warning messages to List methods and update new named selections …
gmalinve Jul 22, 2026
edeb8ab
Merge branch 'main' into feat/create_get_named_selections
gmalinve Jul 22, 2026
40a2b4d
add tests for named selection methods
gmalinve Jul 22, 2026
08e9c35
update docstring
gmalinve Jul 22, 2026
463bdde
update docstrings and logic
gmalinve Jul 22, 2026
2d3d2f8
updates in delete and rename
gmalinve Jul 23, 2026
2a9b2cf
update test
gmalinve Jul 23, 2026
0f37cd8
update implementation
gmalinve Jul 24, 2026
85e5796
updates for faces selection
gmalinve Jul 27, 2026
8b90d6a
updates for faces selection
gmalinve Jul 27, 2026
6ec5f91
Merge branch 'refs/heads/main' into feat/create_get_named_selections
gmalinve Jul 27, 2026
42c7d33
fix UT
gmalinve Jul 27, 2026
ddca879
Merge branch 'main' into feat/create_get_named_selections
gmalinve Jul 27, 2026
991f641
fix test
gmalinve Jul 27, 2026
2d4d2aa
fix test
gmalinve Jul 27, 2026
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/7832.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add new class for named selections
2 changes: 1 addition & 1 deletion src/ansys/aedt/core/icepak.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,9 +355,9 @@ def assign_openings(self, air_faces: list | FacePrimitive) -> BoundaryObject:

"""
boundary_name = generate_unique_name("Opening")
self.modeler.create_face_list(air_faces, "boundary_faces" + boundary_name)
props = {}
air_faces = self.modeler.convert_to_selections(air_faces, True)
self.modeler.create_face_list(air_faces, "boundary_faces" + boundary_name)

props["Faces"] = air_faces
props["Temperature"] = "AmbientTemp"
Expand Down
327 changes: 325 additions & 2 deletions src/ansys/aedt/core/modeler/cad/modeler.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@

from __future__ import annotations

import warnings

from ansys.aedt.core.base import PyAedtBase
from ansys.aedt.core.generic.data_handlers import _dict2arg
from ansys.aedt.core.generic.file_utils import generate_unique_name
Expand All @@ -39,6 +41,7 @@
from ansys.aedt.core.generic.general_methods import settings
from ansys.aedt.core.generic.numbers_utils import _units_assignment
from ansys.aedt.core.generic.quaternion import Quaternion
from ansys.aedt.core.internal.errors import AEDTRuntimeError
from ansys.aedt.core.modeler.cad.elements_3d import EdgePrimitive
from ansys.aedt.core.modeler.cad.elements_3d import FacePrimitive
from ansys.aedt.core.modeler.cad.elements_3d import VertexPrimitive
Expand Down Expand Up @@ -1886,10 +1889,15 @@ class Lists(PropsManager, PyAedtBase):
--------
>>> from ansys.aedt.core.modeler.cad.modeler import Lists
>>> obj = Lists()

"""

def __init__(self, modeler, props=None, name: str | None = None) -> None:
# Deprecated: Lists is replaced by NamedSelections from AEDT 2026.1.
warnings.warn(
"`Lists` is deprecated from AEDT 2026.1. Use `NamedSelections` instead.",
DeprecationWarning,
stacklevel=2,
)
self.auto_update = True
self._modeler = modeler
self.name = name
Expand All @@ -1909,7 +1917,6 @@ def update(self) -> bool:
>>> from ansys.aedt.core.modeler.cad.modeler import Lists
>>> obj = Lists()
>>> obj.update()

"""
# self._change_property(self.name, ["NAME:ChangedProps", ["NAME:Reference CS", "Value:=", self.ref_cs]])
object_list_new = self._list_verification(self.props["List"], self.props["Type"])
Expand Down Expand Up @@ -2072,6 +2079,322 @@ def _list_verification(self, object_list, list_type):
return object_list_new


class NamedSelections(PropsManager, PyAedtBase):
"""Manages Named Selections (replacement for `Lists`) from AEDT version >= 2026.1."""

def __init__(self, modeler, props=None, name: str | None = None) -> None:
self.auto_update = True
self._modeler = modeler
self.name = name
# Reuse ListsProps for the simple properties structure
self.props = ListsProps(self, props)

@pyaedt_function_handler()
def create(
self, assignment: list | str | None = None, name: str | None = None, entity_type: str = "Object"
) -> bool:
"""Create a named selection.

Parameters
----------
assignment : list or str, optional
List of object names or face ids or a comma-separated string.
name : str, optional
Name of the named selection. If not provided a unique name is generated.
entity_type : str optional
Type of the selection: ``"Object"`` or ``"Face"``. Default is ``"Object"``.

Examples
--------
>>> from ansys.aedt.core.modeler.cad.modeler import NamedSelections
>>> m3d = Maxwell3d(version="2026.1")
>>> box1 = m3d.modeler.create_box([1, 1, 1], [5, 2, 5], name="box1")
Create a new instance of NamedSelections
>>> lst1 = NamedSelections(m3d.modeler)
Create a named selection by specifying assignment and entity type
>>> lst1.create(assignment=["box1"], name="my_list", entity_type="Object")
>>> m3d.release_desktop(False, False)

Returns
-------
bool
``True`` when successful.

Raises
------
AEDTRuntimeError
If the operation fails.

References
----------
>>> oEditor.CreateNamedSelection
"""
if not name:
name = generate_unique_name(entity_type + "NamedSelection")

user_list_names = [sel for sel in self._modeler.user_lists if sel.name == name]
if name in user_list_names:
raise ValueError(f"Named selection with name '{name}' already exists.")

# Normalize selection
if isinstance(assignment, (list, tuple)):
if all(isinstance(x, int) for x in assignment):
selection = assignment
sel_type = "Face"
else:
selection = ", ".join([str(x) for x in assignment])
sel_type = entity_type
elif isinstance(assignment, str):
selection = assignment
sel_type = entity_type
else:
selection = ""
sel_type = entity_type

params = ["NAME:NamedSelectionParameters", "Type:=", sel_type, "Selection:=", selection]
attr = ["NAME:Attributes", "Name:=", name, "UDM ID:=", -1]
try:
self._modeler.oeditor.CreateNamedSelection(params, attr)
except Exception:
raise AEDTRuntimeError("Failed to create the named selection.")
else:
props = {"List": assignment, "Type": sel_type, "ID": self._modeler.oeditor.GetNamedSelectionIDByName(name)}
self.props = ListsProps(self, props)
# Keep compatibility with existing storage
self._modeler.user_lists.append(self)
self.name = name
return True

@pyaedt_function_handler()
def delete(self) -> bool:
"""Delete the named selection.

Examples
--------
>>> from ansys.aedt.core import Maxwell3d
>>> aedt_app = Maxwell3d(version="2026.1")
>>> box1 = aedt_app.modeler.create_box([0, 0, 0], [1, 2, 3], name="box1")
>>> box2 = aedt_app.modeler.create_box([10, 10, 10], [1, 2, 3], name="box2")
>>> sel = aedt_app.modeler.create_named_selection(name="test", assignment=aedt_app.modeler.object_names)
>>> sel.delete()
>>> aedt_app.release_desktop()

Returns
-------
bool
``True`` when successful.

Raises
------
AEDTRuntimeError
If the operation fails.

References
----------
>>> oEditor.Delete
"""
self._modeler.oeditor.Delete(["NAME:Selections", "Selections:=", self.name])
self._modeler.user_lists.remove(self)
user_list_names = [sel.name for sel in self._modeler.user_lists]
if self.name not in user_list_names:
return True
else:
raise AEDTRuntimeError("Failed to delete the named selection.")

@pyaedt_function_handler()
def rename(self, name: str) -> bool:
"""Rename the named selection.

Parameters
----------
name : str
New name for the named selection.

Examples
--------
>>> from ansys.aedt.core import Maxwell3d
>>> aedt_app = Maxwell3d(version="2026.1")
>>> box1 = aedt_app.modeler.create_box([0, 0, 0], [1, 2, 3], name="box1")
>>> box2 = aedt_app.modeler.create_box([10, 10, 10], [1, 2, 3], name="box2")
>>> sel = aedt_app.modeler.create_named_selection(name="test", assignment=aedt_app.modeler.object_names)
>>> sel.rename(name="new_test")
>>> aedt_app.release_desktop()

Returns
-------
bool
``True`` when successful.

Raises
------
AEDTRuntimeError
If the operation fails.

References
----------
>>> oEditor.ChangeProperty
"""
argument = [
"NAME:AllTabs",
[
"NAME:Geometry3DListTab",
["NAME:PropServers", self.name],
["NAME:ChangedProps", ["NAME:Name", "Value:=", name]],
],
]
self._modeler.oeditor.ChangeProperty(argument)
old_name = self.name
self.name = name
for sel in self._modeler.user_lists:
if sel is self or sel.name == old_name:
sel.name = name
user_list_names = [sel.name for sel in self._modeler.user_lists]
if name in user_list_names:
self.name = name
return True
else:
raise AEDTRuntimeError("Failed to rename the named selection.")

@pyaedt_function_handler()
def update(self, selection: list | None = None, entity_type: str = "Object", mode: str = "Reassign") -> bool:
"""Update an existing named selection.

This method mirrors the signature and semantics of :class:`Lists.update` for
backward compatibility. If ``selection`` is ``None``, the stored properties
in ``self.props`` are used.

Parameters
----------
selection : list, optional
List of object names or list of FacePrimitive Ids.
If ``None``, uses the selection stored in ``self.props["Selection"]``.
entity_type : str, optional
Type of selection, e.g. ``"Object"`` or ``"Face"``. Default ``"Object"``.
mode : str, optional
Edit mode for the named selection.
Options are: ``"Reassign"``, ``"Add"`,``"Remove"``.
The default value is ``"Reassign"``.

Examples
--------
Update Named Selection that contains objects
>>> from ansys.aedt.core import Maxwell3d
>>> aedt_app = Maxwell3d(version="2026.1")
>>> box1 = aedt_app.modeler.create_box([0, 0, 0], [1, 2, 3], name="box1")
>>> box2 = aedt_app.modeler.create_box([10, 10, 10], [1, 2, 3], name="box2")
>>> sel = aedt_app.modeler.create_named_selection(name="test", assignment=aedt_app.modeler.object_names)
>>> box3 = aedt_app.modeler.create_box([20, 20, 20], [1, 2, 3], name="box3")
Reassign named selection elements
>>> sel.update(selection=[box1.name, box3.name])
Add new element to name selection
>>> sel.update(selection=[box2.name], mode="Add")
Remove element from named selection
>>> sel.update(selection=[box1.name], mode="Remove")
>>> aedt_app.release_desktop()

Update Named Selection that contains faces
>>> from ansys.aedt.core import Maxwell3d
>>> aedt_app = Maxwell3d(version="2026.1")
>>> box1 = aedt_app.modeler.create_box([0, 0, 0], [1, 2, 3], name="box1")
>>> box2 = aedt_app.modeler.create_box([10, 10, 10], [1, 2, 3], name="box2")
>>> ns = aedt_app.modeler.create_named_selection(name="test", assignment=[box1.faces[0], box2.faces[0]])
Add two new faces in Named Selection
>>> ns.update(
... selection=[
... aedt_app.modeler["box2"].faces[1].id,
... aedt_app.modeler["box2"].faces[3].id,
... ],
... entity_type="Face",
... mode="Add",
... )
>>> aedt_app.release_desktop()

Returns
-------
bool
``True`` when successful.

References
----------
>>> oEditor.EditNamedSelection
"""
if mode not in ["Add", "Remove", "Reassign"]:
raise AEDTRuntimeError(f"Invalid mode `{mode}`. Allowed values are `Add`, `Remove`, `Reassign`.")

# If no selection provided raise an exception
if not selection:
raise AEDTRuntimeError("No selection provided to update.")

current_selection = self.props["List"]

object_list_new = self._objects_verification(selection, entity_type)
if entity_type == "Object":
selection = ", ".join(object_list_new)
else:
# For faces, keep a list of ints as EditNamedSelection accepts it
selection = object_list_new

argument1 = ["NAME:Selections", "Selections:=", self.name]
argument2 = [
"NAME:NamedSelectionParameters",
"Type:=",
entity_type,
"Selection:=",
selection,
"Mode:=",
mode,
]
self._modeler.oeditor.EditNamedSelection(argument1, argument2)
# When updating a Named Selection the project must be saved
self._modeler._app.save_project()

# Verify the selection was updated correctly
named_selection_objects = self._modeler.get_named_selection_objects(self.name) or []
if entity_type == "Object":
expected_objects = [obj.name for obj in named_selection_objects]
else:
expected_objects = named_selection_objects
if mode == "Add":
expected_after = current_selection + object_list_new
elif mode == "Remove":
expected_after = [item for item in current_selection if item not in object_list_new]
else: # Reassign
expected_after = object_list_new
# if object_list_new is empty it means that user has provided invalid or non-existing objects.
if not object_list_new or set(expected_after) != set(expected_objects):
raise AEDTRuntimeError("Failed to update the named selection.")
previous_auto_update = self.auto_update
self.auto_update = False
self.props["List"] = expected_after
self.props["Type"] = entity_type
self.auto_update = previous_auto_update
return True

def _objects_verification(self, object_list, list_type):
object_list = self._modeler.convert_to_selections(object_list, True)
object_list_new = []
if list_type == "Object":
obj_names = [i for i in self._modeler.object_names]
# if user passes a non-existing object or an invalid object this check filters it out
check = [item for item in object_list if item in obj_names]
if check:
object_list_new = check
else:
return []

elif list_type == "Face":
object_list_new = []
faces = []
for obj in self._modeler.object_list:
faces.extend(f.id for f in obj.faces)
for face_id in object_list:
if face_id in faces:
object_list_new.append(int(face_id))
if not object_list_new:
return []
return object_list_new


class Modeler(PyAedtBase):
"""Provides the `Modeler` application class that other `Modeler` classes inherit.

Expand Down
Loading
Loading