diff --git a/ansys/mapdl/core/__init__.py b/ansys/mapdl/core/__init__.py index 064a65034b..63862d4473 100644 --- a/ansys/mapdl/core/__init__.py +++ b/ansys/mapdl/core/__init__.py @@ -13,7 +13,7 @@ from pyvista.utilities.sphinx_gallery import _get_sg_image_scraper from ansys.mapdl.core._version import __version__ -from ansys.mapdl.core.convert import convert_script +from ansys.mapdl.core.convert import convert_script, convert_apdl_block from ansys.mapdl.core.launcher import ( launch_mapdl, change_default_ansys_path, diff --git a/ansys/mapdl/core/commands.py b/ansys/mapdl/core/commands.py index 6f359254cd..ae900baaf9 100644 --- a/ansys/mapdl/core/commands.py +++ b/ansys/mapdl/core/commands.py @@ -19,7 +19,7 @@ misc, inq_func ) - +from functools import wraps import re import numpy as np @@ -173,6 +173,7 @@ def inject_docs(docstring): def check_valid_output(func): """Wrapper that check if output can be wrapped by pandas, if not, it will raise an exception.""" + @wraps(func) def func_wrapper(self, *args, **kwargs): output = self.__str__() if '*** WARNING ***' in output or '*** ERROR ***' in output: # Error should be caught in mapdl.run. @@ -571,16 +572,38 @@ def to_array(self): Returns ------- - Numpy array + numpy.ndarray + Numpy array of floats. """ return np.array(self.to_list(), dtype=float) def to_dataframe(self, data=None, columns=None): """Export the command output as a Pandas DataFrame. + Parameters + ---------- + data : numpy.ndarray (structured or homogeneous), Iterable, dict, or DataFrame + The data to be converted to the dataframe values. + Passed directly to the pandas.DataFrame constructor. + Dict can contain Series, arrays, constants, dataclass or list-like objects. If + data is a dict, column order follows insertion-order. + + columns : Index or array-like + Iterable with columns names. + Passed directly to the pandas.DataFrame constructor. + Column labels to use for resulting frame when data does not have them, + defaulting to RangeIndex(0, 1, 2, ..., n). If data contains column labels, + will perform column selection instead. + Returns ------- - Pandas Dataframe + pandas.DataFrame + Pandas DataFrame + + Notes + ----- + The returned dataframe has all its data converted to float + (inheritate from :func:`to_array() ` method). """ try: import pandas as pd @@ -596,10 +619,35 @@ def to_dataframe(self, data=None, columns=None): class BoundaryConditionsListingOutput(CommandListingOutput): + """Allow the conversion of command output to native Python types. + + Custom class for handling the boundary condition listing commands + whose output is sensible to be converted to a list of lists, + or a Pandas DataFrame. + """ + def to_array(self): raise ValueError(MSG_BCListingOutput_to_array) def to_dataframe(self): + """Convert the command output to a Pandas Dataframe. + + Returns + ------- + pandas.DataFrame + Pandas Dataframe + + Notes + ----- + + If present, the next columns will be converted to: + + * ``'NODE'``: int + * ``'LABEL'``: str + * ``'REAL'``: float + * ``'IMAG'``: float + + """ df = super().to_dataframe(data=self.to_list()) if 'NODE' in df.columns: df['NODE'] = df['NODE'].astype(int) @@ -613,4 +661,4 @@ def to_dataframe(self): if 'IMAG' in df.columns: df['IMAG'] = df['IMAG'].astype(float) - return df \ No newline at end of file + return df diff --git a/doc/source/api/commands.rst b/doc/source/api/commands.rst new file mode 100644 index 0000000000..c1f12dd22e --- /dev/null +++ b/doc/source/api/commands.rst @@ -0,0 +1,32 @@ +.. _ref_commands_api: + +Commands Output +=============== + +Various PyMAPDL classes and commands which helps in data post-processing. + +All these classes are subclasses of ``str`` class, hence they inherit all the +methods and attributes of :class:`string`. + +.. currentmodule:: ansys.mapdl.core.commands + + +.. We should add the line ':toctree: _autosummary' to the following classes autosummary + to remove the warning during building, however, it shows only the methods links in the + sidebar (toctree), not the classes, and since both classes have the same method name, it + is confusing. + +.. autoclass:: ansys.mapdl.core.commands.CommandListingOutput + +.. autosummary:: + + CommandListingOutput.to_list + CommandListingOutput.to_array + CommandListingOutput.to_dataframe + +.. autoclass:: ansys.mapdl.core.commands.BoundaryConditionsListingOutput + +.. autosummary:: + + BoundaryConditionsListingOutput.to_list + BoundaryConditionsListingOutput.to_dataframe \ No newline at end of file diff --git a/doc/source/api/index.rst b/doc/source/api/index.rst index 3cf493b805..3382859e5b 100644 --- a/doc/source/api/index.rst +++ b/doc/source/api/index.rst @@ -16,16 +16,18 @@ MAPDL commands mapped to PyMAPDL, see :ref:`ref_mapdl_commands`. :maxdepth: 2 :hidden: + commands + geometry + helper + inline + logging mapdl math - plotting - helper mesh - xpl parameters - geometry + plotting pool post solution - inline - logging + xpl + diff --git a/doc/source/user_guide/convert.rst b/doc/source/user_guide/convert.rst index 9bdc3e0138..149ea6f80d 100644 --- a/doc/source/user_guide/convert.rst +++ b/doc/source/user_guide/convert.rst @@ -39,8 +39,7 @@ using :attr:`Mapdl.parameters ` with: Script Translation ~~~~~~~~~~~~~~~~~~ -Existing ANSYS scripts can be translated using :func:`convert_script() -` +Existing ANSYS scripts can be translated using :func:`convert_script() ` .. code:: python @@ -50,7 +49,7 @@ Existing ANSYS scripts can be translated using :func:`convert_script() pymapdl.convert_script(inputfile, pyscript) Or additionally, you can convert code in form of strings for later processing -using :func:`convert_apdl_block() `: +using :func:`convert_apdl_block() ` : .. code:: python diff --git a/doc/source/user_guide/post.rst b/doc/source/user_guide/post.rst index 5b951d9026..e3be2068df 100644 --- a/doc/source/user_guide/post.rst +++ b/doc/source/user_guide/post.rst @@ -1,9 +1,9 @@ Post-Processing =============== You can post process using an active MAPDL session using the -:attr:`Mapdl.post_processing ` -attrbute of an instance of :class:`Mapdl -`. One advantage of this approach +:class:`Mapdl.post_processing ` +an attribute of an instance of :class:`Mapdl `. +One advantage of this approach is it integrates well with existing MAPDL scripting or automation, but can also be carried out on result files generated from other programs, including ANSYS Mechanical. @@ -23,6 +23,83 @@ streamed back to the client for review or visualization. via a Python client. + +Enriched Command Output +~~~~~~~~~~~~~~~~~~~~~~~ +All :class:`Mapdl ` commands output +a string object which can be parsed to obtain specific data from it. + +In certain :class:`Mapdl ` commands +the returned string contains some methods to process the output. +These commands are listed in Table-1_. + +.. _Table-1: + +**Table 1. Commands with extra processing methods in the output.** + ++----------------+---------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +| Category | Extra Methods Available | Mapdl Commands | ++================+===================================================================================================+==========================================================+ +| **Listing** | * :func:`to_list() ` | * :func:`prcint() ` | +| | * :func:`to_array() ` | * :func:`prenergy() ` | +| | * :func:`to_dataframe() ` | * :func:`prerr() ` | +| | | * :func:`presol() ` | +| | | * :func:`pretab() ` | +| | | * :func:`print() ` | +| | | * :func:`priter() ` | +| | | * :func:`prjsol() ` | +| | | * :func:`prnld() ` | +| | | * :func:`prnsol() ` | +| | | * :func:`prorb() ` | +| | | * :func:`prpath() ` | +| | | * :func:`prrfor() ` | +| | | * :func:`prrsol() ` | +| | | * :func:`prsect() ` | +| | | * :func:`prvect() ` | +| | | * :func:`stat() ` | +| | | * :func:`swlist() ` | ++----------------+---------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +| **Boundary** | * :func:`to_list() ` | * :func:`dlist() ` | +| **Conditions** | * :func:`to_dataframe() ` | * :func:`flist() ` | +| **Listing** | | | ++----------------+---------------------------------------------------------------------------------------------------+----------------------------------------------------------+ + +Here's a simple example demonstrating the the usage: + +.. code:: python + + + >>> from ansys.mapdl.core import launch_mapdl + >>> from ansys.mapdl.core import examples + + >>> mapdl = launch_mapdl() + >>> example = examples.vmfiles['vm10'] + >>> mapdl.input(example) + + >>> mapdl.slashsolu() + >>> mapdl.solve() + + >>> mapdl.post1() + >>> cmd = mapdl.prnsol('U', 'X') + + Output as a list. + + >>> cmd.to_list() + [['1', '0.0000'], ['2', '0.0000']] + + Output as array. + + >>> cmd.to_array() + array([[1., 0.], + [2., 0.]]) + + Output as dataframe. + + >>> cmd.to_dataframe() + NODE UX + 0 1.0 + 1 2.0 + Examples ~~~~~~~~ Classically, one would request nodal results from MAPDL using the @@ -55,8 +132,8 @@ Classically, one would request nodal results from MAPDL using the MORE (YES,NO OR CONTINUOUS)= -However, using an instance of :class:`Mapdl -`, you can instead request the +However, using an instance of :class:`Mapdl `, +you can instead request the nodal displacement with: .. code:: python @@ -82,10 +159,8 @@ Selected Nodes The MAPDL database processes some results independently of if nodes or elements are selected. If you have subselected a certain component and wish to also limit the result of a certain output -(i.e. :func:`nodal_displacement() -`), +use the :attr:`selected_nodes ` attribute to get a mask of the currently selected nodes. .. code::