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

Improving Components API #2471

Merged
merged 24 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
970b610
Improving Component API. Adding items method, and a private method to…
germa89 Nov 2, 2023
e303438
Allowing component retrieval from the mesh grpc module
germa89 Nov 2, 2023
1eae3f7
Using save_selection cont manager
germa89 Nov 2, 2023
8dc36e2
Testing mesh parts
germa89 Nov 2, 2023
33c0b4a
Documenting components API.
germa89 Nov 2, 2023
87ca55f
Fix docstring typo
germa89 Nov 2, 2023
7b657fe
Modifying some examples so they reflect the usage of the new componen…
germa89 Nov 2, 2023
f597c5b
Undoing not deleting temp components
germa89 Nov 2, 2023
0160c9c
Fixing some tests
germa89 Nov 2, 2023
6154655
Disabling Google heading.
germa89 Nov 3, 2023
78122ab
fixing vale version to avoid pipeline unexpected breakdowns.
germa89 Nov 3, 2023
627d423
Undoing changes from main
germa89 Nov 3, 2023
17d06d0
Explanation. pre.
germa89 Nov 3, 2023
6bcd255
Improved tests
germa89 Nov 3, 2023
054e74b
Fixing tests
germa89 Nov 3, 2023
5184e5d
Empty comment to trigger CICD
germa89 Nov 3, 2023
a9b45d0
Created components should be selected.
germa89 Nov 3, 2023
78c74f0
Adding exceptions to `_parse_cmlist*`s when some part of the header i…
germa89 Nov 3, 2023
c1d8e99
Fixing tests
germa89 Nov 3, 2023
e98cd5c
Merge branch 'main' into feat/improving-components-api
germa89 Nov 3, 2023
364050e
Merge branch 'fix/vale-issues' into feat/improving-components-api
germa89 Nov 3, 2023
9480ddf
Merge branch 'main' into feat/improving-components-api
germa89 Nov 3, 2023
4814c09
Merge branch 'main' into feat/improving-components-api
germa89 Nov 6, 2023
d45c14e
Merge branch 'main' into feat/improving-components-api
germa89 Nov 6, 2023
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
97 changes: 97 additions & 0 deletions doc/source/user_guide/components.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@

.. _ref_components:

*******************
Managing components
*******************

MAPDL components can be retrieved and set using
:attr:`Mapdl.components <ansys.mapdl.core.Mapdl.components>`.


There are several ways to create a component in MAPDL.

You can use the :meth:`Mapdl.cm <ansys.mapdl.core.Mapdl.cm>` method:

.. code:: pycon

>>> from ansys.mapdl.core import launch_mapdl
>>> mapdl = launch_mapdl()
>>> mapdl.prep7()
>>> mapdl.block(0, 1, 0, 1, 0, 1)
>>> mapdl.vsel("s", "", "", 1)
>>> mapdl.cm("my_comp", "volu")

Or use higher level syntax. For instance, to set a component
specifying the type and items:

.. code:: pycon

>>> mapdl.components["mycomp3"] = "KP", [1, 2, 3]

Set a component without specifying the type, by default it is ``NODE``:

.. code:: pycon

>>> mapdl.components["mycomp4"] = (1, 2, 3)
/Users/german.ayuso/pymapdl/src/ansys/mapdl/core/component.py:347: UserWarning: Assuming a KP selection.
It is recommended you use the following notation to avoid this warning:
> mapdl.components['mycomp4'] = 'KP' (1, 2, 3)
Alternatively, you disable this warning using:
> mapdl.components.default_entity_warning=False
warnings.warn(

You can change the default type by changing
:attr:`Mapdl.components.default_entity <ansys.mapdl.core.Mapdl.components.default_entity>`

.. code:: pycon

>>> mapdl.components.default_entity = "KP"
>>> mapdl.components["mycomp"] = [1, 2, 3]
>>> mapdl.components["mycomp"].type
'KP'

You can also create a component from already selected entities:

.. code:: pycon

>>> mapdl.lsel("S", 1, 2)
>>> mapdl.components["mylinecomp"] = "LINE"
>>> mapdl.components["mylinecomp"]
(1, 2)


Selecting a component and retrieving it:

.. code:: pycon

>>> mapdl.cmsel("s", "mycomp3")
>>> mapdl.components["mycomp3"]
Component(type='KP', items=(1, 2, 3))


.. note:: Component selection
To being able to access a component through :attr:`Mapdl.components <ansys.mapdl.core.Mapdl.components>`,
the component needs to be selected using :meth:`Mapdl.cmsel() <ansys.mapdl.core.Mapdl.cmsel>`.


Component object
================

The `Component object <ansys.mapdl.core.component.Component>` is the object returned by
:attr:`Mapdl.components <ansys.mapdl.core.Mapdl.components>` when you query it with a component name.
This object has two main attributes: `type <Component.type>` and `items <Component.items>`.
The former returns the component type (`"ELEM"`, `"NODE"`, `"KP"`, etc) and the later returns
a tuple with the index of the entities which belong to that component.

.. code:: pycon

>>> comp = mapdl.components["mycomp3"]
>>> comp.type
'KP'
>>> comp.items
(1, 2, 3)

It should be noticed that the component object is not linked to the MAPDL component, so any change on it
is not reflected in the MAPDL counterpart.

1 change: 1 addition & 0 deletions doc/source/user_guide/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ This section provides a general overview of PyMAPDL and how you use it.
mesh_geometry
post
parameters
components
database
convert
math
Expand Down
3 changes: 2 additions & 1 deletion doc/source/user_guide/parameters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
*********************************
Setting and retrieving parameters
*********************************
APDL parameters can be retrieved from and instance of

MAPDL parameters can be retrieved from an instance of
:class:`Mapdl <ansys.mapdl.core.mapdl._MapdlCore>`
using the :attr:`Mapdl.parameters <ansys.mapdl.core.Mapdl.parameters>`.
For example, if you want to use MAPDL's
Expand Down
8 changes: 4 additions & 4 deletions examples/00-mapdl-examples/2d_pressure_vessel.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def pipe_plane_strain(e, nu, inn_radius, out_radius, press, aesize):
# We perform plane strain analysis on one quadrant (0deg - 90deg) of the
# pressure vessel
mapdl.pcirc(inn_radius, out_radius, theta1=0, theta2=90)
mapdl.cm("PIPE_PROFILE", "AREA")
mapdl.components["PIPE_PROFILE"] = "AREA"

# Define material properties
mapdl.mp("EX", 1, e) # Youngs modulus
Expand All @@ -88,14 +88,14 @@ def pipe_plane_strain(e, nu, inn_radius, out_radius, press, aesize):

# Create components for defining loads and constraints
mapdl.nsel("S", "LOC", "X", 0) # Select nodes on top left edge
mapdl.cm("X_FIXED", "NODES") # Create nodal component
mapdl.components["X_FIXED"] = "NODES" # Create nodal component

mapdl.nsel("S", "LOC", "Y", 0) # Select nodes on bottom right edge
mapdl.cm("Y_FIXED", "NODES") # Create nodal component
mapdl.components["Y_FIXED"] = "NODES" # Create nodal component
mapdl.allsel()

mapdl.lsel("S", "RADIUS", vmin=rad1) # Select the line along inner radius
mapdl.cm("PRESSURE_EDGE", "LINE") # Create a line component
mapdl.components["PRESSURE_EDGE"] = "LINE" # Create a line component
mapdl.allsel()

# Define solution controls
Expand Down
14 changes: 7 additions & 7 deletions examples/00-mapdl-examples/composite_dcb.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,19 +145,19 @@
mapdl.geometry.area_select(areas[0], "r")
mapdl.nsla("r", 1)
mapdl.nsel("r", "loc", "x", pre_crack, length + pre_crack + eps)
mapdl.cm("cm_1", "node")
mapdl.components["cm_1"] = "node"

mapdl.allsel()
mapdl.asel("s", "loc", "z", 1.7)
areas = mapdl.geometry.anum
mapdl.geometry.area_select(areas[1], "r")
mapdl.nsla("r", 1)
mapdl.nsel("r", "loc", "x", pre_crack, length + pre_crack + eps)
mapdl.cm("cm_2", "node")
mapdl.components["cm_2"] = "node"

# Identify all the elements before generation of TARGE170 elements
mapdl.allsel()
mapdl.cm("_elemcm", "elem")
mapdl.components["_elemcm"] = "elem"
mapdl.mat(2)

# Assign real constants and key options
Expand All @@ -181,15 +181,15 @@

# Generate TARGE170 elements on top of cm_1
mapdl.nsel("s", "", "", "cm_1")
mapdl.cm("_target", "node")
mapdl.components["_target"] = "node"
mapdl.type(2)
mapdl.esln("s", 0)
mapdl.esurf()

# Generate CONTA174 elements on top of cm_2
mapdl.cmsel("s", "_elemcm")
mapdl.nsel("s", "", "", "cm_2")
mapdl.cm("_contact", "node")
mapdl.components["_contact"] = "node"
mapdl.type(3)
mapdl.esln("s", 0)
mapdl.esurf()
Expand All @@ -211,13 +211,13 @@
mapdl.nsel(type_="s", item="loc", comp="x", vmin=0.0, vmax=0.0)
mapdl.nsel(type_="r", item="loc", comp="z", vmin=2 * height, vmax=2 * height)
mapdl.d(node="all", lab="uz", value=d)
mapdl.cm("top_nod", "node")
mapdl.components["top_nod"] = "node"

mapdl.allsel()
mapdl.nsel(type_="s", item="loc", comp="x", vmin=0.0, vmax=0.0)
mapdl.nsel(type_="r", item="loc", comp="z", vmin=0.0, vmax=0.0)
mapdl.d(node="all", lab="uz", value=-10)
mapdl.cm("bot_nod", "node")
mapdl.components["bot_nod"] = "node"

# Apply the fix condition
mapdl.allsel()
Expand Down
47 changes: 31 additions & 16 deletions src/ansys/mapdl/core/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ def type(self) -> ENTITIES_TYP:
"""Return the type of the component. For instance "NODES", "KP", etc."""
return self._type

@property
def items(self) -> tuple:
"""Return the ids of the entities in the component."""
return tuple(self)


class ComponentManager:
"""Collection of MAPDL components.
Expand Down Expand Up @@ -175,15 +180,17 @@ class ComponentManager:
Set a component without specifying the type, by default it is ``NODE``:

>>> mapdl.components["mycomp4"] = (1, 2, 3)
/Users/german.ayuso/pymapdl/src/ansys/mapdl/core/component.py:282: UserWarning: Assuming a NODES selection.
It is recommended you use the following notation to avoid this warning:
\>\>\> mapdl.components['mycomp3'] = 'NODES' (1, 2, 3)
Alternatively, you disable this warning using:
> mapdl.components.default_entity_warning=False
warnings.warn(

You can change the default type by changing
:attr:`Mapdl.components.default_entity <ansys.mapdl.core.Mapdl.components.default_entity>`

>>> mapdl.component.default_entity = "KP"
/Users/german.ayuso/pymapdl/src/ansys/mapdl/core/component.py:282: UserWarning: Assuming a NODES selection.
It is recommended you use the following notation to avoid this warning:
\>\>\> mapdl.components['mycomp3'] = 'NODES' (1, 2, 3)
Alternatively, you disable this warning using
>>> mapdl.component["mycomp] = [1, 2, 3]
>>> mapdl.component["mycomp"].type
'KP'
Expand Down Expand Up @@ -274,7 +281,6 @@ def _comp(self, value):
self.__comp = value

def __getitem__(self, key: str) -> ITEMS_VALUES:
self._comp = self._mapdl._parse_cmlist()
forced_to_select = False

if key.upper() not in self._comp and self._autoselect_components:
Expand Down Expand Up @@ -388,19 +394,17 @@ def __setitem__(self, key: str, value: ITEMS_VALUES) -> None:

_check_valid_pyobj_to_entities(cmitems)

# Save current selection
self._mapdl.cm("__temp__", cmtype)

# Select the cmitems entities
func = getattr(self._mapdl, ENTITIES_MAPPING[cmtype].lower())
func(type_="S", vmin=cmitems)
# Using context manager to proper save the selections (including CM)
with self._mapdl.save_selection:
# Select the cmitems entities
func = getattr(self._mapdl, ENTITIES_MAPPING[cmtype].lower())
func(type_="S", vmin=cmitems)

# create component
self._mapdl.cm(cmname, cmtype)
# create component
self._mapdl.cm(cmname, cmtype)

# reselecting previous selection
self._mapdl.cmsel("S", "__temp__")
self._mapdl.cmdele("__temp__")
# adding newly created selection
self._mapdl.cmsel("A", cmname)

def __repr__(self) -> str:
"""Return the current components in a pretty format"""
Expand Down Expand Up @@ -499,3 +503,14 @@ def select(self, names: Union[str, list[str], tuple[str]], mute=False) -> None:
self._mapdl.cmsel("S", each_name, mute=mute)
else:
self._mapdl.cmsel("A", each_name, mute=mute)

def _get_all_components_type(self, type_: ENTITIES_TYP):
"""Returns a dict with all the components which type matches the entity type"""
dict_ = {}
for each_comp in self._comp:
item = self.__getitem__(each_comp)
i_type_ = item.type
i_items = item.items
if i_type_ == type_:
dict_[each_comp] = i_items
return dict_
27 changes: 20 additions & 7 deletions src/ansys/mapdl/core/mapdl.py
Original file line number Diff line number Diff line change
Expand Up @@ -4911,12 +4911,19 @@ def _parse_cmlist(self, cmlist: Optional[str] = None) -> Dict[str, Any]:
if not cmlist:
cmlist = self.cmlist()

header = "NAME TYPE SUBCOMPONENTS"
blocks = re.findall(
r"(?s)NAME\s+TYPE\s+SUBCOMPONENTS\s+(.*?)\s*(?=\n\s*\n|\Z)",
cmlist,
flags=re.DOTALL,
)
if "NAME" in cmlist and "SUBCOMPONENTS" in cmlist:
# header
# "NAME TYPE SUBCOMPONENTS"
blocks = re.findall(
r"(?s)NAME\s+TYPE\s+SUBCOMPONENTS\s+(.*?)\s*(?=\n\s*\n|\Z)",
cmlist,
flags=re.DOTALL,
)
elif "LIST ALL SELECTED COMPONENTS":
blocks = cmlist.splitlines()[1:]
else:
raise ValueError("The format of the CMLIST output is not recognaised.")

cmlist = "\n".join(blocks)

def extract(each_line, ind):
Expand All @@ -4934,9 +4941,15 @@ def _parse_cmlist_indiv(
if not cmlist:
cmlist = self.cmlist(cmname, 1)
# Capturing blocks
if "NAME" in cmlist and "SUBCOMPONENTS" in cmlist:
header = r"NAME\s+TYPE\s+SUBCOMPONENTS"

elif "LIST COMPONENT" in cmlist:
header = ""

cmlist = "\n\n".join(
re.findall(
r"(?s)NAME\s+TYPE\s+SUBCOMPONENTS\s+(.*?)\s*(?=\n\s*\n|\Z)",
r"(?s)" + header + r"\s+(.*?)\s*(?=\n\s*\n|\Z)",
cmlist,
flags=re.DOTALL,
)
Expand Down
6 changes: 2 additions & 4 deletions src/ansys/mapdl/core/mesh_grpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ def _reset_cache(self):
self._cached_elements = None # cached list of elements
self._chunk_size = None
self._elem = None
self._elem_comps = {}
self._elem_off = None
self._enum = None # cached element numbering
self._esys = None # cached element coordinate system
Expand All @@ -117,7 +116,6 @@ def _reset_cache(self):
self._mtype = None # cached ansys material type
self._nnum = None
self._node_angles = None # cached node angles
self._node_comps = {}
self._node_coord = None # cached node coordinates
self._rcon = None # cached ansys element real constant
self._rdat = None
Expand Down Expand Up @@ -325,7 +323,7 @@ def element_components(self):
array of MAPDL element numbers corresponding to the element
component. The keys are element component names.
"""
return self._elem_comps
return self._mapdl.components._get_all_components_type("ELEM")

@property
def node_components(self):
Expand All @@ -335,7 +333,7 @@ def node_components(self):
array of MAPDL node numbers corresponding to the node
component. The keys are node component names.
"""
return self._node_comps
return self._mapdl.components._get_all_components_type("NODE")

@property
@requires_model()
Expand Down
Loading
Loading