From ff8ea46490eced9734f829a0bdb85f5b6e1277ed Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Mon, 6 Nov 2023 13:29:46 +0100 Subject: [PATCH 01/30] Fixing plot indexing (#2476) * Disabling Google heading. Adding `mapdl` (lowercase) to accepts. Fixing other warnings. * fixing vale version to avoid pipeline unexpected breakdowns. * Undoing changes from main * Explanation. pre. * Improved tests * Empty comment to trigger CICD * Using theoretical calculations (and longer approach)... I guess there is no shortcuts in life! * Improving testing --- src/ansys/mapdl/core/post.py | 58 +++++++++++++++++++++++++++++------- tests/test_post.py | 35 ++++++++++++++++++++-- 2 files changed, 80 insertions(+), 13 deletions(-) diff --git a/src/ansys/mapdl/core/post.py b/src/ansys/mapdl/core/post.py index c802f32ba7..b2d4b596b2 100644 --- a/src/ansys/mapdl/core/post.py +++ b/src/ansys/mapdl/core/post.py @@ -351,7 +351,7 @@ def element_values(self, item, comp="", option="AVG") -> np.ndarray: Returns ------- numpy.ndarray - Numpy array containing the requested element values for ta + Numpy array containing the requested element values for a given item and component. Notes @@ -632,27 +632,63 @@ def _plot_cell_scalars(self, scalars, show_elem_numbering=False, **kwargs): surf = self._mapdl.mesh._surf - # as ``disp`` returns the result for all nodes, we need all node numbers + # as ``disp`` returns the result for all nodes/elems, we need all node/elem numbers # and to index to the output node numbers if hasattr(self._mapdl.mesh, "enum_all"): - enum = self._mapdl.mesh.enum + enum = self._mapdl.mesh.enum_all else: enum = self._all_enum - # it's possible that there are duplicated element numbers, - # therefore we need to get the unique values and a reverse index + ####################################################################### + # Bool operations + # =============== + # I'm going to explain this clearly because it can be confusing for the + # future developers (me). + # This explanation is based in scalars (`element_values`) NOT having the + # full elements (selected and not selected) size. + # + # First, it's possible that there are duplicated element numbers, + # in the surf object returned by Pyvista. + # Therefore we need to get the unique values and a reverse index, to + # later convert the MAPDL values to Pyvista values. uni, ridx = np.unique(surf["ansys_elem_num"], return_inverse=True) - mask = np.isin(enum, uni, assume_unique=True) - - if scalars.size != mask.size: - scalars = scalars[self.selected_elements] - scalars = scalars[mask][ridx] + # which means that, uni is the id of mapdl elements in the polydata + # object. These elements does not need to be in order, and there can be + # duplicated! + # Hence: + # uni[ridx] = surf["ansys_elem_num"] + # + # Let's notice that: + # * enum[self.selected_elements] is mapdl selected elements ids in MAPDL notation. + # + # Theoretical approach + # -------------------- + # The theoretical approach will be using an intermediate array of the + # size of the MAPDL total number of elements (we do not care about selected). + # + values = np.zeros(enum.shape) + # + # Then assign the MAPDL values for the selected element (scalars) + # + values[self.selected_elements] = scalars + # + # Because values are in order, but with python notation, then we can do: + # + surf_values = values[ + uni - 1 + ] # -1 to set MAPDL element indexing to python indexing + # + # Then to account for the original Pyvista object: + # + surf_values = surf_values[ridx] + # + ####################################################################### meshes = [ { "mesh": surf.copy(deep=False), # deep=False for ipyvtk-simple "scalar_bar_args": {"title": kwargs.pop("stitle", "")}, - "scalars": scalars, + "scalars": surf_values, } ] diff --git a/tests/test_post.py b/tests/test_post.py index fdbf24d702..387f662fa6 100644 --- a/tests/test_post.py +++ b/tests/test_post.py @@ -765,13 +765,44 @@ def test_plot_incomplete_element_selection(mapdl, contact_solve): mapdl.esel("S", "ELEM", "", 1, mapdl.mesh.n_elem // 2) assert mapdl.post_processing.plot_element_displacement() is None + mapdl.nsel("S", "NODE", "", 1, mapdl.mesh.n_elem // 2, 2) + assert mapdl.post_processing.plot_element_displacement() is None + + mapdl.nsel("S", "NODE", "", 5, mapdl.mesh.n_elem // 2, 2) + assert mapdl.post_processing.plot_element_displacement() is None + + mapdl.vsel("s", "", "", 1) + mapdl.eslv("s") + assert mapdl.post_processing.plot_element_displacement() is None + + mapdl.vsel("s", "", "", 2) + mapdl.eslv("s") + assert mapdl.post_processing.plot_element_displacement() is None + @requires("pyvista") -@pytest.mark.xfail(strict=False, reason="The image regression is failing. See #2435") -def test_plot_incomplete_nodal_selection(mapdl, contact_solve): +def test_plot_incomplete_nodal_selection(mapdl, contact_solve, verify_image_cache): + verify_image_cache.skip = True + mapdl.nsel("S", "NODE", "", 1, mapdl.mesh.n_node // 2) assert mapdl.post_processing.plot_nodal_displacement() is None + mapdl.nsel("S", "NODE", "", 1, mapdl.mesh.n_node // 2, 2) + assert mapdl.post_processing.plot_nodal_displacement() is None + + mapdl.nsel("S", "NODE", "", 5, mapdl.mesh.n_node // 2, 2) + assert mapdl.post_processing.plot_nodal_displacement() is None + + mapdl.vsel("s", "", "", 1) + mapdl.eslv("S") + mapdl.nsle("S") + assert mapdl.post_processing.plot_nodal_displacement() is None + + mapdl.vsel("s", "", "", 2) + mapdl.eslv("S") + mapdl.nsle("S") + assert mapdl.post_processing.plot_nodal_displacement() is None + @requires("pyvista") def test_general_plotter_returns(mapdl, static_solve, verify_image_cache): From 4706f5a6b4a34dee51fbf948b5cfc372bad87048 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Tue, 7 Nov 2023 18:17:19 +0100 Subject: [PATCH 02/30] Adding global unit test duration limit (#2485) * Adding duration limit globally * Increasing timeout --- .ci/run_vms.py | 3 ++- .github/workflows/ci.yml | 1 + pyproject.toml | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.ci/run_vms.py b/.ci/run_vms.py index 087513ff83..8b1e7f8262 100644 --- a/.ci/run_vms.py +++ b/.ci/run_vms.py @@ -2,7 +2,7 @@ from ansys.mapdl.core import launch_mapdl from ansys.mapdl.core.examples import vmfiles -mapdl = launch_mapdl() +mapdl = launch_mapdl(start_timeout=100) vms = list(vmfiles.keys()) @@ -11,4 +11,5 @@ print(f"Running the vm {i}: {vm}") output = mapdl.input(vmfiles[vm]) print(f"Running the vm {i}: Successfully completed") + mapdl.exit() diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0986a3c11d..c427f667bf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -477,6 +477,7 @@ jobs: env: ON_LOCAL: true ON_UBUNTU: true + PYTEST_TIMEOUT: 120 # seconds. Limit the duration for each unit test steps: - name: "Install Git and checkout project" diff --git a/pyproject.toml b/pyproject.toml index a7e2f1fb0f..8386027703 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -76,6 +76,7 @@ tests = [ "vtk==9.2.6", "pytest-rerunfailures==12.0", "pytest-pyvista==0.1.9", + "pytest-timeout==2.2.0", ] doc = [ "sphinx==7.2.6", From 1835ef3cac62e4a38538971296e61f8dd98f9750 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Tue, 7 Nov 2023 18:19:35 +0100 Subject: [PATCH 03/30] Improving Components API (#2471) * Improving Component API. Adding items method, and a private method to return all the components from a given entity type. * Allowing component retrieval from the mesh grpc module * Using save_selection cont manager Testing components * Testing mesh parts * Documenting components API. * Fix docstring typo * Modifying some examples so they reflect the usage of the new component API * Undoing not deleting temp components * Fixing some tests * Disabling Google heading. Adding `mapdl` (lowercase) to accepts. Fixing other warnings. * fixing vale version to avoid pipeline unexpected breakdowns. * Undoing changes from main * Explanation. pre. * Improved tests * Fixing tests * Empty comment to trigger CICD * Created components should be selected. * Adding exceptions to `_parse_cmlist*`s when some part of the header is missing. * Fixing tests --- doc/source/user_guide/components.rst | 97 +++++++++++++++++++ doc/source/user_guide/index.rst | 1 + doc/source/user_guide/parameters.rst | 3 +- .../00-mapdl-examples/2d_pressure_vessel.py | 8 +- examples/00-mapdl-examples/composite_dcb.py | 14 +-- src/ansys/mapdl/core/component.py | 47 ++++++--- src/ansys/mapdl/core/mapdl.py | 27 ++++-- src/ansys/mapdl/core/mesh_grpc.py | 6 +- tests/test_component.py | 34 ++++++- tests/test_mesh_grpc.py | 58 ++++++++++- 10 files changed, 253 insertions(+), 42 deletions(-) create mode 100644 doc/source/user_guide/components.rst diff --git a/doc/source/user_guide/components.rst b/doc/source/user_guide/components.rst new file mode 100644 index 0000000000..4b0e8603d9 --- /dev/null +++ b/doc/source/user_guide/components.rst @@ -0,0 +1,97 @@ + +.. _ref_components: + +******************* +Managing components +******************* + +MAPDL components can be retrieved and set using +:attr:`Mapdl.components `. + + +There are several ways to create a component in MAPDL. + +You can use the :meth:`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 ` + +.. 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 `, + the component needs to be selected using :meth:`Mapdl.cmsel() `. + + +Component object +================ + +The `Component object ` is the object returned by +:attr:`Mapdl.components ` when you query it with a component name. +This object has two main attributes: `type ` and `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. + diff --git a/doc/source/user_guide/index.rst b/doc/source/user_guide/index.rst index e94fbbc485..ca2df903cb 100644 --- a/doc/source/user_guide/index.rst +++ b/doc/source/user_guide/index.rst @@ -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 diff --git a/doc/source/user_guide/parameters.rst b/doc/source/user_guide/parameters.rst index f8cf0a8739..51a3453b44 100644 --- a/doc/source/user_guide/parameters.rst +++ b/doc/source/user_guide/parameters.rst @@ -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 ` using the :attr:`Mapdl.parameters `. For example, if you want to use MAPDL's diff --git a/examples/00-mapdl-examples/2d_pressure_vessel.py b/examples/00-mapdl-examples/2d_pressure_vessel.py index f9eaa5c64a..ea0ac50c36 100644 --- a/examples/00-mapdl-examples/2d_pressure_vessel.py +++ b/examples/00-mapdl-examples/2d_pressure_vessel.py @@ -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 @@ -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 diff --git a/examples/00-mapdl-examples/composite_dcb.py b/examples/00-mapdl-examples/composite_dcb.py index 5879160dee..a8b2093d09 100644 --- a/examples/00-mapdl-examples/composite_dcb.py +++ b/examples/00-mapdl-examples/composite_dcb.py @@ -145,7 +145,7 @@ 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) @@ -153,11 +153,11 @@ 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 @@ -181,7 +181,7 @@ # 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() @@ -189,7 +189,7 @@ # 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() @@ -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() diff --git a/src/ansys/mapdl/core/component.py b/src/ansys/mapdl/core/component.py index ef67f93458..c32e0f9530 100644 --- a/src/ansys/mapdl/core/component.py +++ b/src/ansys/mapdl/core/component.py @@ -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. @@ -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 ` >>> 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' @@ -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: @@ -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""" @@ -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_ diff --git a/src/ansys/mapdl/core/mapdl.py b/src/ansys/mapdl/core/mapdl.py index 1a526b2aaa..16144d18e9 100644 --- a/src/ansys/mapdl/core/mapdl.py +++ b/src/ansys/mapdl/core/mapdl.py @@ -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): @@ -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, ) diff --git a/src/ansys/mapdl/core/mesh_grpc.py b/src/ansys/mapdl/core/mesh_grpc.py index 95dc61565c..d9e5c69f30 100644 --- a/src/ansys/mapdl/core/mesh_grpc.py +++ b/src/ansys/mapdl/core/mesh_grpc.py @@ -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 @@ -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 @@ -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): @@ -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() diff --git a/tests/test_component.py b/tests/test_component.py index b76f3d7140..c4807be74a 100644 --- a/tests/test_component.py +++ b/tests/test_component.py @@ -43,7 +43,7 @@ def test_set_item(mapdl, cube_geom_and_mesh, type_): mapdl.components[comp_name] = type_, [1, 2, 3] cm_ = mapdl.run("cmlist").upper() - assert comp_name not in cm_ + assert comp_name in cm_ # the component should be selected already after creation mapdl.cmsel("S", comp_name) cm_ = mapdl.run("cmlist").upper() @@ -68,6 +68,7 @@ def test_set_item_no_type(mapdl, cube_geom_and_mesh): def test_get_item(mapdl, cube_geom_and_mesh): mapdl.components["mycomp"] = "node", [1, 2, 3] + mapdl.cmsel("NONE") with pytest.raises(ComponentIsNotSelected): mapdl.components["mycomp"] @@ -83,6 +84,7 @@ def test_get_item(mapdl, cube_geom_and_mesh): def test_get_item_autoselect_components(mapdl, cube_geom_and_mesh): mapdl.components["mycomp"] = "node", [1, 2, 3] + mapdl.cmsel("NONE") mapdl.components._autoselect_components = True cm_ = mapdl.run("cmlist").upper() @@ -268,3 +270,33 @@ def test_dunder_methods_types(mapdl, basic_components): def test_dunder_methods_items(mapdl, basic_components): assert [("MYCOMP1", "NODE"), ("MYCOMP2", "KP")] == list(mapdl.components.items()) + + +def test__get_all_components_type(mapdl, cube_geom_and_mesh): + mapdl.allsel() + mapdl.esel("s", "", "", 1) + mapdl.nsel("s", "", "", 1) + mapdl.cm("cmelem", "ELEM") + mapdl.cm("cmnodes", "NODE") + + mapdl.nsel("a", "", "", 2) + mapdl.esel("a", "", "", 2) + mapdl.cm("cmnodes2", "NODE") + mapdl.cm("cmelem2", "ELEM") + + comp_elem = mapdl.components._get_all_components_type("ELEM") + + expected_output = {"CMELEM": (1,), "CMELEM2": (1, 2)} + assert comp_elem + assert comp_elem == expected_output + assert "CMNODES" not in comp_elem + assert "CMNODES2" not in comp_elem + + # Nodes + comp_nodes = mapdl.components._get_all_components_type("NODE") + + expected_output = {"CMNODES": (1,), "CMNODES2": (1, 2)} + assert comp_nodes + assert comp_nodes == expected_output + assert "CMELEM" not in comp_nodes + assert "CMELEM2" not in comp_nodes diff --git a/tests/test_mesh_grpc.py b/tests/test_mesh_grpc.py index 40de300285..ed44252e33 100644 --- a/tests/test_mesh_grpc.py +++ b/tests/test_mesh_grpc.py @@ -104,6 +104,53 @@ def test_empty_mesh(mapdl, cleared): mapdl.mesh.save("file.vtk") +def test_element_node_components(mapdl, contact_geom_and_mesh): + mapdl.allsel() + assert not mapdl.mesh.element_components + assert "MYELEMCOMP" not in mapdl.mesh.element_components + + assert mapdl.mesh.node_components + assert "TN.TGT" in mapdl.mesh.node_components + assert "CMNODE" not in mapdl.mesh.node_components + + mapdl.cmsel("NONE") + mapdl.cm("CMNODE", "NODE") + mapdl.components["MYELEMCOMP"] = "ELEM", (1, 2, 3) + + assert mapdl.mesh.element_components + assert "MYELEMCOMP" in mapdl.mesh.element_components + + assert mapdl.mesh.node_components + assert "TN.TGT" not in mapdl.mesh.node_components + assert "CMNODE" in mapdl.mesh.node_components + + mapdl.cmsel("NONE") + assert not mapdl.mesh.element_components + assert "MYELEMCOMP" not in mapdl.mesh.element_components + + assert not mapdl.mesh.node_components + assert "TN.TGT" not in mapdl.mesh.node_components + assert "CMNODE" not in mapdl.mesh.node_components + + mapdl.cmsel("S", "MYELEMCOMP") + assert mapdl.mesh.element_components + assert "MYELEMCOMP" in mapdl.mesh.element_components + + assert not mapdl.mesh.node_components + assert "TN.TGT" not in mapdl.mesh.node_components + assert "CMNODE" not in mapdl.mesh.node_components + + mapdl.cmsel("S", "CMNODE") + assert mapdl.mesh.node_components + assert "CMNODE" in mapdl.mesh.node_components + assert "TN.TGT" not in mapdl.mesh.node_components + + mapdl.cmsel("all") + assert mapdl.mesh.node_components + assert "TN.TGT" in mapdl.mesh.node_components + assert "CMNODE" in mapdl.mesh.node_components + + def test_non_empty_mesh(mapdl, contact_geom_and_mesh): assert mapdl.mesh.n_node > 0 assert mapdl.mesh.n_elem > 0 @@ -134,8 +181,15 @@ def test_non_empty_mesh(mapdl, contact_geom_and_mesh): assert mapdl.mesh.tshape_key assert len(mapdl.mesh.tshape_key.keys()) > 0 - # assert mapdl.mesh.element_components #Not implemented - # assert mapdl.mesh.node_components # Not implemented + mapdl.allsel() + mapdl.cmsel("all") + mapdl.cm("CMNODE", "NODE") + mapdl.components["MYELEMCOMP"] = "ELEM", (1, 2, 3) + + assert mapdl.mesh.element_components + assert "MYELEMCOMP" in mapdl.mesh.element_components + assert mapdl.mesh.node_components + assert "CMNODE" in mapdl.mesh.node_components # bools assert mapdl.mesh._has_elements From c1ea52cd5117e9882c7e5cf509a2f38938c9303d Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Tue, 7 Nov 2023 18:24:38 +0100 Subject: [PATCH 04/30] Fix always asking for multiline output. (#2467) --- src/ansys/mapdl/core/mapdl.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ansys/mapdl/core/mapdl.py b/src/ansys/mapdl/core/mapdl.py index 16144d18e9..3f89c5e2dd 100644 --- a/src/ansys/mapdl/core/mapdl.py +++ b/src/ansys/mapdl/core/mapdl.py @@ -2860,9 +2860,10 @@ def get( value = response.split("=")[-1].strip() if item3: - self._log.info( - f"The command '{command}' is showing the next message: '{value.splitlines()[1].strip()}'" - ) + if len(value.splitlines()) > 1: + self._log.info( + f"The command '{command}' is showing the next message: '{value.splitlines()[1].strip()}'" + ) value = value.splitlines()[0] try: # always either a float or string From e1668a139ce16c28efa901ae5dc8e9b37d386d7a Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Wed, 8 Nov 2023 10:37:58 +0100 Subject: [PATCH 05/30] Removing vm step from minimal. It is buggy. (#2492) --- .ci/run_vms.py | 15 --------------- .github/workflows/ci.yml | 6 ------ 2 files changed, 21 deletions(-) delete mode 100644 .ci/run_vms.py diff --git a/.ci/run_vms.py b/.ci/run_vms.py deleted file mode 100644 index 8b1e7f8262..0000000000 --- a/.ci/run_vms.py +++ /dev/null @@ -1,15 +0,0 @@ -"""Run some vm manuals""" -from ansys.mapdl.core import launch_mapdl -from ansys.mapdl.core.examples import vmfiles - -mapdl = launch_mapdl(start_timeout=100) - -vms = list(vmfiles.keys()) - -for i, vm in enumerate(vms[:2]): - mapdl.clear() - print(f"Running the vm {i}: {vm}") - output = mapdl.input(vmfiles[vm]) - print(f"Running the vm {i}: Successfully completed") - -mapdl.exit() diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c427f667bf..e3de78c98a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -628,12 +628,6 @@ jobs: python -m pip install . --no-deps python -m pip install -r minimum_requirements.txt python -c "from ansys.mapdl import core as pymapdl; print('Import successfull')" - - - name: "Running some verification manual examples" - run: | - unset PYMAPDL_START_INSTANCE - export ANSYSLMD_LICENSE_FILE=1055@${{ secrets.LICENSE_SERVER }} - python .ci/run_vms.py - name: "Unit testing requirements installation" run: | From cc169bf8ea07392c1b8e754c46aeeb13e80f42f9 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Wed, 8 Nov 2023 10:43:03 +0100 Subject: [PATCH 06/30] Referencing the PDF in the docs (#2489) --- doc/source/conf.py | 2 ++ doc/source/index.rst | 2 ++ doc/source/links.rst | 3 +++ 3 files changed, 7 insertions(+) diff --git a/doc/source/conf.py b/doc/source/conf.py index 8656edc17e..fa8399d4e0 100755 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -181,6 +181,8 @@ rst_epilog += f.read() rst_epilog = rst_epilog.replace("%%VERSION%%", "v231") +rst_epilog = rst_epilog.replace("%%PYMAPDLVERSION%%", release) + # Read link all substitutions from file with open("substitutions.rst") as f: diff --git a/doc/source/index.rst b/doc/source/index.rst index e6186ff38b..fe5c6ff1c9 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -166,6 +166,8 @@ Documentation and issues ------------------------ Documentation for the latest stable release of PyMAPDL is hosted at `PyMAPDL documentation `_. +The same documentation is also `available as PDF `_ in the `Assets` section in the +`latest GitHub package release `_. In the upper right corner of the documentation's title bar, there is an option for switching from viewing the documentation for the latest stable release to viewing the documentation for the diff --git a/doc/source/links.rst b/doc/source/links.rst index 984799e0de..a4a445b702 100644 --- a/doc/source/links.rst +++ b/doc/source/links.rst @@ -148,6 +148,9 @@ .. _pymapdl_discussion_differences_mapdl_pymapdl: https://github.com/ansys/pymapdl-reader/issues/185 .. _cartpole_example_notebook: https://cartpole.mapdl.docs.pyansys.com/ml-rl-notebook.html .. _wsl_launching_mapdl: https://github.com/ansys/pymapdl/issues/2315 +.. _pymapdl_latest_github_release: https://github.com/ansys/pymapdl/releases/latest +.. _pymapdl_latest_pdf_doc: https://github.com/ansys/pymapdl/releases/download/v%%PYMAPDLVERSION%%.0/pymapdl-Documentation-%%PYMAPDLVERSION%%.0.pdf + .. #Python .. _using_venv: https://docs.python.org/3/library/venv.html From 1cbc03746f7f41036a5e7d9dd8125424034504cf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 8 Nov 2023 09:45:32 +0000 Subject: [PATCH 07/30] [pre-commit.ci] pre-commit autoupdate (#2482) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/codespell-project/codespell: v2.2.2 → v2.2.4](https://github.com/codespell-project/codespell/compare/v2.2.2...v2.2.4) - [github.com/python-jsonschema/check-jsonschema: 0.21.0 → 0.22.0](https://github.com/python-jsonschema/check-jsonschema/compare/0.21.0...0.22.0) * Fixing codespell * Fixing pre-commit * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * simplifying accepted words list * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/psf/black: 23.1.0 → 23.3.0](https://github.com/psf/black/compare/23.1.0...23.3.0) * Updating also blackend * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/adamchainz/blacken-docs: 1.13.0 → 1.14.0](https://github.com/adamchainz/blacken-docs/compare/1.13.0...1.14.0) - [github.com/codespell-project/codespell: v2.2.4 → v2.2.5](https://github.com/codespell-project/codespell/compare/v2.2.4...v2.2.5) - [github.com/python-jsonschema/check-jsonschema: 0.23.1 → 0.23.2](https://github.com/python-jsonschema/check-jsonschema/compare/0.23.1...0.23.2) * removing vale warnings * Adding words to ignore * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/psf/black: 23.10.0 → 23.10.1](https://github.com/psf/black/compare/23.10.0...23.10.1) * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/python-jsonschema/check-jsonschema: 0.27.0 → 0.27.1](https://github.com/python-jsonschema/check-jsonschema/compare/0.27.0...0.27.1) --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: German Co-authored-by: German <28149841+germa89@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ec1c50a2f6..38a72d5fe6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -60,6 +60,6 @@ repos: # this validates our github workflow files - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.27.0 + rev: 0.27.1 hooks: - id: check-github-workflows From 7674756045db3895da2407c47242b61d8170ba6d Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Wed, 8 Nov 2023 13:32:14 +0100 Subject: [PATCH 08/30] Implementing memory limitations in dockerizer jobs (#2483) * Testing if env vars are allowed in container options * Testing options * Testing multiline * removing ticks * Using one line * Adding units * Adding options to docker run --- .ci/start_mapdl.sh | 3 +++ .ci/start_mapdl_ubuntu.sh | 3 +++ .github/workflows/ci.yml | 4 ++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.ci/start_mapdl.sh b/.ci/start_mapdl.sh index 8d71fa8e02..170f7c0284 100755 --- a/.ci/start_mapdl.sh +++ b/.ci/start_mapdl.sh @@ -14,6 +14,9 @@ docker run \ -p $PYMAPDL_DB_PORT:50055 \ --shm-size=1gb \ -e I_MPI_SHM_LMT=shm \ + --oom-kill-disable \ + --memory=6656MB \ + --memory-swap=16896MB \ $MAPDL_IMAGE \ -$DISTRIBUTED_MODE -np 2 > log.txt & grep -q 'Server listening on' <(timeout 60 tail -f log.txt) diff --git a/.ci/start_mapdl_ubuntu.sh b/.ci/start_mapdl_ubuntu.sh index 2165e2b079..2e3f511dae 100755 --- a/.ci/start_mapdl_ubuntu.sh +++ b/.ci/start_mapdl_ubuntu.sh @@ -17,5 +17,8 @@ docker run \ -e I_MPI_SHM_LMT=shm \ -w /jobs \ -u=0:0 \ + --oom-kill-disable \ + --memory=6656MB \ + --memory-swap=16896MB \ $MAPDL_IMAGE /ansys_inc/v222/ansys/bin/mapdl -grpc -dir /jobs -$DISTRIBUTED_MODE -np 2 > log.txt & grep -q 'Server listening on' <(timeout 60 tail -f log.txt) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3de78c98a..58966a26c7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -470,7 +470,7 @@ jobs: commit_long_sha: ${{ steps.attatch-to-pr.outputs.commit_long_sha }} container: image: ghcr.io/ansys/mapdl:v22.2-ubuntu - options: "-u=0:0 --entrypoint /bin/bash" + options: -u=0:0 --oom-kill-disable --memory=6656MB --memory-swap=16896MB --shm-size=1gb --entrypoint /bin/bash credentials: username: ${{ secrets.GH_USERNAME }} password: ${{ secrets.GITHUB_TOKEN }} @@ -596,7 +596,7 @@ jobs: timeout-minutes: 55 container: image: ghcr.io/ansys/mapdl:v22.2-ubuntu - options: "-u=0:0 --entrypoint /bin/bash" + options: -u=0:0 --oom-kill-disable --memory=6656MB --memory-swap=16896MB --shm-size=1gb --entrypoint /bin/bash credentials: username: ${{ secrets.GH_USERNAME }} password: ${{ secrets.GITHUB_TOKEN }} From 428fba2fdaf0291497006fba84aa6dc47b15cb08 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Wed, 8 Nov 2023 16:48:38 +0100 Subject: [PATCH 09/30] Avoiding running `get_array` and `non_interactive` raising exceptions (#2484) * * Not running `get_array` in `non_interactive` * Clarifying exceptions messages * Early exit of `non_interactive` cont manager when an exception is raised inside. * avoiding raising exception in main thread * Fixing ealry exit of `non_interactive` cont man. * removing checking main thread --- src/ansys/mapdl/core/mapdl.py | 43 +++++++++++++++++++++++++++--- src/ansys/mapdl/core/mapdl_grpc.py | 6 +++-- tests/test_mapdl.py | 7 +++++ 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/ansys/mapdl/core/mapdl.py b/src/ansys/mapdl/core/mapdl.py index 3f89c5e2dd..c64ca5b3b6 100644 --- a/src/ansys/mapdl/core/mapdl.py +++ b/src/ansys/mapdl/core/mapdl.py @@ -826,10 +826,20 @@ def __enter__(self): self._parent()._store_commands = True def __exit__(self, *args): - self._parent()._log.debug("Exiting non-interactive mode") - self._parent()._flush_stored() self._parent()._store_commands = False + if args[0] is not None: + # An exception was raised, let's exit now without flushing + self._parent()._log.debug( + "An exception was found in the `non_interactive` environment. " + "Hence the commands are not flushed." + ) + return None + else: + # No exception so let's flush. + self._parent()._log.debug("Exiting non-interactive mode") + self._parent()._flush_stored() + class _save_selection: """Save the selection and returns to it when exiting""" @@ -3827,7 +3837,20 @@ def get_array( -0.00178402, -0.01234851, 0.01234851, -0.01234851]) """ - arr = self._get_array(entity, entnum, item1, it1num, item2, it2num, kloop) + parm_name = kwargs.get("parm", None) + + if self._store_commands: + raise MapdlRuntimeError( + "Cannot use `mapdl.get_array` when in `non_interactive` mode, " + "since it does not return anything until the `non_interactive` context " + "manager is finished.\n" + "Exit `non_interactive` mode before using this method.\n\n" + "Alternatively you can use `mapdl.vget` to specify the name of the MAPDL parameter where to store the retrieved value." + ) + + arr = self._get_array( + entity, entnum, item1, it1num, item2, it2num, kloop, **kwargs + ) # edge case where corba refuses to return the array ntry = 0 @@ -3853,6 +3876,16 @@ def _get_array( """Uses the VGET command to get an array from ANSYS""" parm_name = kwargs.pop("parm", None) + if self._store_commands and not parm_name: + raise MapdlRuntimeError( + "Cannot use `mapdl._get_array` when in `non_interactive` mode, " + "since it does not return anything until the `non_interactive` context " + "manager is finished.\n" + "Exit `non_interactive` mode before using this method.\n\n" + "Alternatively you can use `mapdl.vget` or use the `parm` kwarg in " + "`mapdl._get_array` to specify the name of the MAPDL parameter where to store the retrieved value. In any case, this function will return `None`" + ) + if parm_name is None: parm_name = "__vget_tmp_%d__" % self._vget_arr_counter self._vget_arr_counter += 1 @@ -3869,6 +3902,10 @@ def _get_array( mute=False, ) + if self._store_commands: + # Return early + return None + # check if empty array if "the dimension number 1 is 0" in out: return np.empty(0) diff --git a/src/ansys/mapdl/core/mapdl_grpc.py b/src/ansys/mapdl/core/mapdl_grpc.py index 3cdf013779..33b6ca9725 100644 --- a/src/ansys/mapdl/core/mapdl_grpc.py +++ b/src/ansys/mapdl/core/mapdl_grpc.py @@ -2040,8 +2040,10 @@ def _get( if self._store_commands: raise MapdlRuntimeError( - "Cannot use gRPC enabled ``GET`` when in non_interactive mode. " - "Exit non_interactive mode before using this method." + "Cannot use `mapdl.get_value` when in `non_interactive` mode. " + "Exit non_interactive mode before using this method.\n\n" + "Alternatively you can use `mapdl.get` to specify the name of " + "the MAPDL parameter where to store the retrieved value.\n" ) cmd = f"{entity},{entnum},{item1},{it1num},{item2},{it2num},{item3}, {it3num}, {item4}, {it4num}" diff --git a/tests/test_mapdl.py b/tests/test_mapdl.py index bab5602e29..e46df07a95 100644 --- a/tests/test_mapdl.py +++ b/tests/test_mapdl.py @@ -2117,3 +2117,10 @@ def test_saving_selection_context(mapdl, cube_solve): assert "nod_selection_4".upper() not in mapdl.cmlist() assert "nod_selection_4" not in mapdl.components + + +def test_get_array_non_interactive(mapdl, solved_box): + mapdl.allsel() + with pytest.raises(MapdlRuntimeError): + with mapdl.non_interactive: + mapdl.get_array("asdf", "2") From 949b8d83c33bd09e33b163fa1b27e414f97d93d0 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Wed, 8 Nov 2023 17:14:05 +0100 Subject: [PATCH 10/30] Delaying codecov report until CI is finished (#2495) * testing wait for ci * using after_n_build --- codecov.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/codecov.yml b/codecov.yml index 0fa76adb8f..5d4ef18f65 100644 --- a/codecov.yml +++ b/codecov.yml @@ -25,3 +25,11 @@ coverage: if_ci_failed: error if_no_uploads: error threshold: 4% # Because some tests are flaky. + +codecov: + notify: + wait_for_ci: yes + # do not notify until at least 5 builds have been uploaded from the CI pipeline + after_n_builds: 5 + comment: + after_n_builds: 5 \ No newline at end of file From 286f90e0fe4163b6b126a63a446187b31a93f2aa Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Mon, 20 Nov 2023 15:23:26 +0100 Subject: [PATCH 11/30] Fixing CICD: Adding missing `libgomp1` dependency (#2514) * Reducing the amount to time * testing launching MAPDL * moving step to minimal * testing MAPDL launcher * testing missing library * adding sudo update * Adding -y * check * Adding missing package to ubuntu local * Removing stuff * Revert "Reducing the amount to time" This reverts commit c4cdd05386e081bcfe60efb86dbfad7deb69239a. --- .github/workflows/ci.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 58966a26c7..becb5eaceb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -502,7 +502,7 @@ jobs: - name: "Install OS packages" run: | apt update - apt install -y libgl1-mesa-glx xvfb + apt install -y libgl1-mesa-glx xvfb libgomp1 - name: "Test virtual framebuffer" run: | @@ -629,6 +629,11 @@ jobs: python -m pip install -r minimum_requirements.txt python -c "from ansys.mapdl import core as pymapdl; print('Import successfull')" + - name: "Installing missing package" + run: | + sudo apt-get update + sudo apt-get install -y libgomp1 + - name: "Unit testing requirements installation" run: | python -m pip install pytest pytest-rerunfailures pytest-cov From 3539a12d73a104294a54ed973c72a3b29465a33d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 14:49:23 +0000 Subject: [PATCH 12/30] Bump numpy from 1.26.1 to 1.26.2 (#2513) Bumps [numpy](https://github.com/numpy/numpy) from 1.26.1 to 1.26.2. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](https://github.com/numpy/numpy/compare/v1.26.1...v1.26.2) --- updated-dependencies: - dependency-name: numpy dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- minimum_requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/minimum_requirements.txt b/minimum_requirements.txt index be7a8b7caa..bae8c96518 100644 --- a/minimum_requirements.txt +++ b/minimum_requirements.txt @@ -1,6 +1,6 @@ ansys-api-mapdl==0.5.1 importlib-metadata==6.8.0 -numpy==1.26.1 +numpy==1.26.2 platformdirs==3.11.0 psutil==5.9.6 pyansys-tools-versioning==0.5.0 From 6d36efb384137058c48aa19faad3601f27623674 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 14:49:40 +0000 Subject: [PATCH 13/30] Bump sphinx-reredirects from 0.1.2 to 0.1.3 (#2497) Bumps [sphinx-reredirects](https://github.com/documatt/sphinx-reredirects) from 0.1.2 to 0.1.3. - [Commits](https://github.com/documatt/sphinx-reredirects/compare/v0.1.2...v0.1.3) --- updated-dependencies: - dependency-name: sphinx-reredirects dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 8386027703..36f092723c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -103,7 +103,7 @@ doc = [ "sphinx-gallery==0.14.0", "sphinxcontrib-websupport==1.2.6", "sphinxemoji==0.2.0", - "sphinx-reredirects==0.1.2", + "sphinx-reredirects==0.1.3", "vtk==9.2.6", "sphinx_design==0.5.0", ] From cf5e195f4e86c0b852b6ec61955e2a62eeef3a1b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 14:50:43 +0000 Subject: [PATCH 14/30] Bump sphinx-autodoc-typehints from 1.24.1 to 1.25.2 (#2512) Bumps [sphinx-autodoc-typehints](https://github.com/tox-dev/sphinx-autodoc-typehints) from 1.24.1 to 1.25.2. - [Release notes](https://github.com/tox-dev/sphinx-autodoc-typehints/releases) - [Changelog](https://github.com/tox-dev/sphinx-autodoc-typehints/blob/main/CHANGELOG.md) - [Commits](https://github.com/tox-dev/sphinx-autodoc-typehints/compare/1.24.1...1.25.2) --- updated-dependencies: - dependency-name: sphinx-autodoc-typehints dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 36f092723c..de01f78669 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,7 +98,7 @@ doc = [ "pythreejs==2.4.2", "pyvista[trame]==0.42.3", "sphinx-autobuild==2021.3.14", - "sphinx-autodoc-typehints==1.24.1", + "sphinx-autodoc-typehints==1.25.2", "sphinx-copybutton==0.5.2", "sphinx-gallery==0.14.0", "sphinxcontrib-websupport==1.2.6", From 987bf4b628066f71823b35086177c4159359ba8b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 14:51:51 +0000 Subject: [PATCH 15/30] Bump ansys-mapdl-reader from 0.52.20 to 0.53.0 (#2511) Bumps [ansys-mapdl-reader](https://github.com/pyansys/pymapdl-reader) from 0.52.20 to 0.53.0. - [Release notes](https://github.com/pyansys/pymapdl-reader/releases) - [Commits](https://github.com/pyansys/pymapdl-reader/compare/v0.52.20...v0.53.0) --- updated-dependencies: - dependency-name: ansys-mapdl-reader dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index de01f78669..d4fc064dc2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -81,7 +81,7 @@ tests = [ doc = [ "sphinx==7.2.6", "ansys-dpf-core==0.10.0", - "ansys-mapdl-reader==0.52.20", + "ansys-mapdl-reader==0.53.0", "ansys-sphinx-theme==0.12.4", "grpcio==1.51.1", "imageio-ffmpeg==0.4.9", From e7b8cd1527b80cc011b61aa648124b74f9b50fe9 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Mon, 20 Nov 2023 15:54:56 +0100 Subject: [PATCH 16/30] Reducing README to avoid duplicity (#2490) --- README.rst | 166 ++--------------------------------------------------- 1 file changed, 4 insertions(+), 162 deletions(-) diff --git a/README.rst b/README.rst index 1dbb9c915a..5a5df7d442 100644 --- a/README.rst +++ b/README.rst @@ -34,6 +34,7 @@ PyMAPDL Overview -------- + The PyMAPDL project supports Pythonic access to MAPDL to be able to communicate with the MAPDL process directly from Python. The latest ``ansys-mapdl-core`` package enables a more comprehensive interface with @@ -68,6 +69,9 @@ You can also `view `_ + On the `PyMAPDL Issues `_ page, you can create issues to report bugs and request new features. On the `PyMAPDL Discussions `_ page or the `Discussions `_ @@ -102,168 +106,6 @@ split up into the following projects and modules: For more information on each project, visit their GitHub pages. -Installation ------------- -The ``ansys-mapdl-core`` package currently supports Python 3.8 through -Python 3.11 on Windows, Mac OS, and Linux. - -Install the latest release from `PyPi -`_ with: - -.. code:: console - - pip install ansys-mapdl-core - -If you are planning to use PyMAPDL together with `Jupyter lab `_, -you can install both in one step: - -.. code:: console - - pip install 'ansys-mapdl-core[jupyter]' - - -Alternatively, install the latest from `PyMAPDL GitHub -`_ via: - -.. code:: console - - pip install git+https://github.com/ansys/pymapdl.git - - -For a local "development" version, install with (requires pip >= 22.0): - -.. code:: console - - git clone https://github.com/ansys/pymapdl.git - cd pymapdl - pip install -e . - - -Offline installation -~~~~~~~~~~~~~~~~~~~~ -If you lack an internet connection on your install machine, the recommended way -of installing PyMAPDL is downloading the wheelhouse archive from the `Releases -Page `_ for your corresponding -machine architecture. - -Each wheelhouse archive contains all the python wheels necessary to install -PyMAPDL from scratch on Windows and Linux for Python 3.8 and 3.11. You can install -this on an isolated system with a fresh python or on a virtual environment. - -For example, on Linux Ubuntu with Python 3.10, unzip it and install it with the following: - -.. code:: console - - unzip ansys-mapdl-core-v0.65.0-wheelhouse-ubuntu-latest-3.10.zip - wheelhouse - pip install ansys-mapdl-core -f wheelhouse --no-index --upgrade --ignore-installed - -If you're on Windows with Python 3.10, unzip manually to a ``wheelhouse`` directory and -install using the same command as above. - -Consider installing using a `virtual environment -`_. - - -Dependencies ------------- -You must have a local licenced copy of Ansys to run MAPDL prior and -including 2021R1. If you have the latest version of 2021R1 you do -not need MAPDL installed locally and can connect to a remote instance. - - -Getting started ---------------- - -Launch MAPDL locally -~~~~~~~~~~~~~~~~~~~~ -You can launch MAPDL locally directly from Python using ``launch_mapdl``: - -.. code:: python - - from ansys.mapdl.core import launch_mapdl - - mapdl = launch_mapdl() - -This automatically searches for the latest local version of MAPDL, -launches it as a background process, and immediately connects to it. -You can then start sending python commands to MAPDL. - - -Launching manually or connecting to a remote instance -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you want to connect to a session of MAPDL on a remote computer -(either locally the LAN or through the internet), first ensure you -have MAPDL started in gRPC server mode. This example assumes that you -are launching an instance locally from Windows, but it can be easily -adapted to run from Linux, or the LAN provided the necessary ports are -open. This example specifies the port with ``-port 50052``, but this -option can be left out if you plan on using the default port 50052. - -.. code:: pwsh-session - - start "MAPDL" "%ANSYS211_DIR%\bin\winx64\ANSYS211.exe" -port 50052 -grpc - -Next, connect to the instance of MAPDL from python with: - -.. code:: pycon - - >>> from ansys.mapdl.core import Mapdl - >>> ip = "127.0.0.1" - >>> mapdl = Mapdl(ip=ip, port=50052, start_instance=False) - >>> print(mapdl) - - -A successful connection returns: - -.. code:: output - - Product: ANSYS Mechanical Enterprise - MAPDL Version: RELEASE 2020 R2 BUILD 20.2TEST UPDATE 20200601 - ansys.mapdl.core Version: 0.57.0 - - -Should you want to connect to this instance of MAPDL from a remote -computer, you substitute ``ip=`` with the LAN or WAN address of the -computer you wish to connect to. Depending on your network settings, -you may have to open local ports or enable port redirection across the -WAN. - - -Basic usage -~~~~~~~~~~~ -You run MAPDL commands via: - -.. code:: python - - mapdl.run("/PREP7") - - -Nearly all the built-in MAPDL commands have an associated pythonic -method mapped to it. For example, `/PREP7` is: - -.. code:: python - - mapdl.prep7() - - -There are also non-mapdl commands such as ``mapdl.eplot`` which plot -elements using ``vtk`` and ``pyvista`` rather than relying on MAPDL's -graphics server. Another is ``mapdl.vget``, which leverages gRPC to -rapidly exchange binary arrays from MAPDL to Python rather than -relying on file IO to exchange data. - -Additionally, there are the ``post_processing``, ``geometry``, and -``mesh`` properties, which you can use to perform remote (or local) -post processing without result file exchange, display geometry -properties, or view mesh statistics. Additionally, there's the -``parameters`` property which shows the active MAPDL parameters, and -you can use to send or receive arrays between MAPDL and Python. - -For more information, see the full documentation at `PyMAPDL Documentation -`_. - Citing this module ------------------- If you use ``PyMAPDL`` for research and would like to cite the module From c6309364b3f55978cb63259cb63d17a0e7c05369 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 15:07:18 +0000 Subject: [PATCH 17/30] Bump imageio from 2.31.6 to 2.33.0 (#2516) Bumps [imageio](https://github.com/imageio/imageio) from 2.31.6 to 2.33.0. - [Release notes](https://github.com/imageio/imageio/releases) - [Changelog](https://github.com/imageio/imageio/blob/master/CHANGELOG.md) - [Commits](https://github.com/imageio/imageio/compare/v2.31.6...v2.33.0) --- updated-dependencies: - dependency-name: imageio dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d4fc064dc2..56fe4c160f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -85,7 +85,7 @@ doc = [ "ansys-sphinx-theme==0.12.4", "grpcio==1.51.1", "imageio-ffmpeg==0.4.9", - "imageio==2.31.6", + "imageio==2.33.0", "jupyter_sphinx==0.4.0", "jupyterlab>=3.2.8", "matplotlib==3.8.1", From ccb50506f8876ff93fa291669f865b1f9bf8239b Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Mon, 20 Nov 2023 16:15:27 +0100 Subject: [PATCH 18/30] Removing skip regression check cli argument (#2487) * Removing skip regression check cli argument * Removing pytest-pyvista argument --- .github/workflows/ci.yml | 1 - tests/conftest.py | 12 ------------ 2 files changed, 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index becb5eaceb..5af6400a7e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -644,7 +644,6 @@ jobs: export ANSYSLMD_LICENSE_FILE=1055@${{ secrets.LICENSE_SERVER }} pytest -k "not test_dpf" \ ${{ env.PYTEST_ARGUMENTS }} \ - --skip-regression-check \ --cov-report=xml:ubuntu-v22.2.0-local-minimal.xml - uses: codecov/codecov-action@v3 diff --git a/tests/conftest.py b/tests/conftest.py index 364728c27f..70732888c8 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -245,12 +245,6 @@ def pytest_addoption(parser): default=False, help="run only GUI tests", ) - parser.addoption( - "--skip-regression-check", - action="store_true", - default=False, - help="Avoid checking the image regression check in all tests", - ) def pytest_collection_modifyitems(config, items): @@ -302,13 +296,7 @@ def pytest_collection_modifyitems(config, items): @pytest.fixture(autouse=True) def wrapped_verify_image_cache(verify_image_cache, pytestconfig): - # Checking if we want to avoid the check using pytest cli. - skip_regression_check = pytestconfig.option.skip_regression_check - if skip_regression_check: - verify_image_cache.skip = True - # Configuration - # default check verify_image_cache.error_value = 500.0 verify_image_cache.warning_value = 200.0 From 44c4c47361d528d6f5466980ad1bc5cc09cab66f Mon Sep 17 00:00:00 2001 From: Roberto Pastor Muela <37798125+RobPasMue@users.noreply.github.com> Date: Mon, 20 Nov 2023 16:29:58 +0100 Subject: [PATCH 19/30] feat: add support for Python 3.12 (#2507) * feat: add support for Python 3.12 * fix: upper limit in pyptoject.toml * update pymapdl reader --------- Co-authored-by: Camille <78221213+clatapie@users.noreply.github.com> Co-authored-by: German <28149841+germa89@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/bug.yml | 1 + .github/ISSUE_TEMPLATE/examples.yml | 1 + .github/workflows/ci.yml | 2 +- doc/source/getting_started/index.rst | 2 +- doc/source/user_guide/upf.rst | 2 +- pyproject.toml | 3 ++- tox.ini | 3 ++- 7 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index eb62d83bf2..8224f3b373 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -84,6 +84,7 @@ body: - '3.9' - '3.10' - '3.11' + - '3.12' validations: required: false diff --git a/.github/ISSUE_TEMPLATE/examples.yml b/.github/ISSUE_TEMPLATE/examples.yml index a99d340d60..d2d1cfb715 100644 --- a/.github/ISSUE_TEMPLATE/examples.yml +++ b/.github/ISSUE_TEMPLATE/examples.yml @@ -60,6 +60,7 @@ body: - '3.9' - '3.10' - '3.11' + - '3.12' validations: required: true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5af6400a7e..3f7c465643 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,7 +77,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] - python-version: ['3.8', '3.9', '3.10', '3.11'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] # Only perform wheelhouse builds for macOS when releasing should-release: - ${{ github.event_name == 'push' && contains(github.ref, 'refs/tags') }} diff --git a/doc/source/getting_started/index.rst b/doc/source/getting_started/index.rst index 9d122919a0..75d5f6cfda 100644 --- a/doc/source/getting_started/index.rst +++ b/doc/source/getting_started/index.rst @@ -35,7 +35,7 @@ Installation Python module ~~~~~~~~~~~~~ The ``ansys.mapdl.core`` package currently supports Python 3.8 through -Python 3.11 on Windows, Mac OS, and Linux. +Python 3.12 on Windows, Mac OS, and Linux. Install the latest release from `PyPi `_ with: diff --git a/doc/source/user_guide/upf.rst b/doc/source/user_guide/upf.rst index 280fadc0fa..a72a337c6c 100644 --- a/doc/source/user_guide/upf.rst +++ b/doc/source/user_guide/upf.rst @@ -10,7 +10,7 @@ documented UPF subroutines support the Python UPF capability. For more informati see `Supported UPF subroutines`_). You must install a Python distribution before using this feature. Python 3.8 -through Python 3.11 are supported. +through Python 3.12 are supported. Python UPFs are only supported on Linux. diff --git a/pyproject.toml b/pyproject.toml index 56fe4c160f..54a128774e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ name = "ansys-mapdl-core" version = "0.68.dev0" description = "A Python wrapper for Ansys MAPDL." readme = "README.rst" -requires-python = ">=3.8,<3.12" +requires-python = ">=3.8,<3.13" license = {file = "LICENSE"} authors = [ {name = "Ansys, Inc.", email = "pyansys.maintainers@ansys.com"}, @@ -52,6 +52,7 @@ classifiers = [ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ] [project.optional-dependencies] diff --git a/tox.ini b/tox.ini index 872396338c..f510d23321 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] description = Default tox environments list envlist = - style,{py37,py38,py39,py310}{,-coverage},doc + style,{py38,py39,py310,py311,py312}{,-coverage},doc skip_missing_interpreters = true isolated_build = true isolated_build_env = build @@ -13,6 +13,7 @@ basepython = py39: python3.9 py310: python3.10 py311: python3.11 + py312: python3.12 py: python3 {style,reformat,doc}: python3 setenv = From 571aae2a6781589b48df6d79abc6a92e631d446c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 16:07:03 +0000 Subject: [PATCH 20/30] [pre-commit.ci] pre-commit autoupdate (#2504) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/codespell-project/codespell: v2.2.2 → v2.2.4](https://github.com/codespell-project/codespell/compare/v2.2.2...v2.2.4) - [github.com/python-jsonschema/check-jsonschema: 0.21.0 → 0.22.0](https://github.com/python-jsonschema/check-jsonschema/compare/0.21.0...0.22.0) * Fixing codespell * Fixing pre-commit * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * simplifying accepted words list * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/psf/black: 23.1.0 → 23.3.0](https://github.com/psf/black/compare/23.1.0...23.3.0) * Updating also blackend * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/adamchainz/blacken-docs: 1.13.0 → 1.14.0](https://github.com/adamchainz/blacken-docs/compare/1.13.0...1.14.0) - [github.com/codespell-project/codespell: v2.2.4 → v2.2.5](https://github.com/codespell-project/codespell/compare/v2.2.4...v2.2.5) - [github.com/python-jsonschema/check-jsonschema: 0.23.1 → 0.23.2](https://github.com/python-jsonschema/check-jsonschema/compare/0.23.1...0.23.2) * removing vale warnings * Adding words to ignore * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/psf/black: 23.10.0 → 23.10.1](https://github.com/psf/black/compare/23.10.0...23.10.1) * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/python-jsonschema/check-jsonschema: 0.27.0 → 0.27.1](https://github.com/python-jsonschema/check-jsonschema/compare/0.27.0...0.27.1) * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/psf/black: 23.10.1 → 23.11.0](https://github.com/psf/black/compare/23.10.1...23.11.0) --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: German --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 38a72d5fe6..b479d3e3d8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,7 +21,7 @@ repos: ) - repo: https://github.com/psf/black - rev: 23.10.1 # IF VERSION CHANGES --> MODIFY "blacken-docs" MANUALLY AS WELL!! + rev: 23.11.0 # IF VERSION CHANGES --> MODIFY "blacken-docs" MANUALLY AS WELL!! hooks: - id: black args: @@ -31,7 +31,7 @@ repos: rev: 1.16.0 hooks: - id: blacken-docs - additional_dependencies: [black==23.10.1] + additional_dependencies: [black==23.11.0] - repo: https://github.com/PyCQA/flake8 rev: 6.1.0 From cbadf1886403d01fc1a0bc3b0861e75a7e1deb98 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Tue, 21 Nov 2023 11:33:18 +0100 Subject: [PATCH 21/30] Improve launcher documentation (#2488) * * Reorg of getting started. * Update versions * Small fixes * Fixing vale * Shortening line * Apply suggestions from code review Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * typo * typos * first windows commands, later linux. Making those bold titled. --------- Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> --- doc/source/getting_started/contribution.rst | 4 +- doc/source/getting_started/docker.rst | 23 +- doc/source/getting_started/faq.rst | 27 +- doc/source/getting_started/index.rst | 116 +-------- doc/source/getting_started/install_mapdl.rst | 56 +++++ .../getting_started/install_pymapdl.rst | 84 +++++++ doc/source/getting_started/launcher.rst | 235 ++++++++++++++++++ doc/source/getting_started/running_mapdl.rst | 145 ----------- doc/source/getting_started/using_julia.rst | 4 +- doc/source/index.rst | 7 +- doc/source/links.rst | 2 +- doc/source/user_guide/index.rst | 35 ++- doc/source/user_guide/launcher.rst | 84 ------- doc/source/user_guide/mapdl.rst | 2 +- doc/source/user_guide/troubleshoot.rst | 60 +++-- examples/00-mapdl-examples/lathe_cutter.py | 4 +- src/ansys/mapdl/core/misc.py | 8 +- src/ansys/mapdl/core/pool.py | 10 +- 18 files changed, 486 insertions(+), 420 deletions(-) create mode 100644 doc/source/getting_started/install_mapdl.rst create mode 100644 doc/source/getting_started/install_pymapdl.rst create mode 100644 doc/source/getting_started/launcher.rst delete mode 100644 doc/source/getting_started/running_mapdl.rst delete mode 100644 doc/source/user_guide/launcher.rst diff --git a/doc/source/getting_started/contribution.rst b/doc/source/getting_started/contribution.rst index 5be0ac5c19..8c2662d325 100644 --- a/doc/source/getting_started/contribution.rst +++ b/doc/source/getting_started/contribution.rst @@ -58,7 +58,7 @@ Testing MAPDL If you do not have MAPDL installed locally but still want to run the unit testing, you must set up the following environment variables. -In Windows, use: +**On Windows** .. code:: pwsh-session @@ -66,7 +66,7 @@ In Windows, use: SET PYMAPDL_PORT= (default 50052) SET PYMAPDL_IP= (default 127.0.0.1) -In Linux, use: +**On Linux** .. code:: console diff --git a/doc/source/getting_started/docker.rst b/doc/source/getting_started/docker.rst index c1a6ff5b54..e892b3268f 100644 --- a/doc/source/getting_started/docker.rst +++ b/doc/source/getting_started/docker.rst @@ -85,15 +85,6 @@ container. To instantiate an MAPDL Docker container from an image hosted at ``ghcr.io/myuser/myrepo/mymapdldockerimage``, use code like in the following examples. -**On Linux** - -.. code:: bash - - ANSYSLMD_LICENSE_FILE=1055@MY_LICENSE_SERVER_IP - LOCAL_MAPDL_PORT=50053 - MAPDL_DOCKER_REGISTRY_URL=ghcr.io/myuser/myrepo/mymapdldockerimage - docker run -e ANSYSLMD_LICENSE_FILE=$ANSYSLMD_LICENSE_FILE --restart always --name mapdl -p $LOCAL_MAPDL_PORT:50052 $MAPDL_DOCKER_REGISTRY_URL -smp > log.txt - **On Windows** .. code:: pwsh-session @@ -105,6 +96,16 @@ use code like in the following examples. docker run -e ANSYSLMD_LICENSE_FILE=$env:ANSYSLMD_LICENSE_FILE --restart always --name mapdl -p $env:LOCAL_MAPDL_PORT`:50052 $env:MAPDL_DOCKER_REGISTRY_URL -smp +**On Linux** + +.. code:: bash + + ANSYSLMD_LICENSE_FILE=1055@MY_LICENSE_SERVER_IP + LOCAL_MAPDL_PORT=50053 + MAPDL_DOCKER_REGISTRY_URL=ghcr.io/myuser/myrepo/mymapdldockerimage + docker run -e ANSYSLMD_LICENSE_FILE=$ANSYSLMD_LICENSE_FILE --restart always --name mapdl -p $LOCAL_MAPDL_PORT:50052 $MAPDL_DOCKER_REGISTRY_URL -smp > log.txt + + The first time you instantiate the container, Docker logins into the registry and pulls the required image. This can take some time, depending on the size of the image. @@ -162,10 +163,10 @@ number available on the host machine) with the ``-np`` switch: For additional command line arguments, see the *Notes* section in the -description for the :func:`launch_mapdl() ` +description for the :func:`launch_mapdl() ` function. -You can use a script file (batch ``'.bat'`` or PowerShell ``'.ps'``) +You can use a script file (batch ``".bat"`` or PowerShell ``".ps"``). to run the preceding commands all at once. Once you have launched MAPDL, you should see the following content diff --git a/doc/source/getting_started/faq.rst b/doc/source/getting_started/faq.rst index 818e09e33e..f18f980150 100644 --- a/doc/source/getting_started/faq.rst +++ b/doc/source/getting_started/faq.rst @@ -7,11 +7,15 @@ Frequently asked questions How do you report issues? ========================= -To report bugs and documentation errors and to make feature requests, use the `PyMAPDL issues `_ page of -the GitHub repository. +If you find an issue, the first place to visit for possible solutions is the :ref:`troubleshooting section `. -To ask more open-ended questions or seek advice from the community, use the `PyMAPDL discussions `_ page -of the GitHub repository. +If you do not find a solution there, you can search for your issue within the `GitHub repository `_. You can use `the search box `_ to find related issues or pull requests. + +To ask more open-ended questions or seek advice from the community, +use the `PyMAPDL discussions `_ page of the GitHub repository. + +To report bugs and documentation errors and to make feature requests, +use the `PyMAPDL issues `_ page of the GitHub repository. What are the pros and cons of PyMAPDL versus Ansys ACT? @@ -44,12 +48,15 @@ like to develop software. Has APDL been "deprecated" by Ansys? If so, what does that mean for PyMAPDL? ============================================================================ -APDL isn't going anywhere. In fact, whenever you call Mechanical Workbench, it's generating an input file -(``ds.dat``) that's fed into MAPDL. However, what's changed over the past several years is where the geometry, -meshing, and postprocessing is occurring. Geometry generation can take place within SpaceClaim or Design Modeler, -and meshing is done using a variety of new and powerful meshers within Workbench. While these tools are -far superior to the ones in MAPDL, their biggest limitation is that they're difficult to script -(especially externally). As a result, there are still users who choose to generate the geometry and mesh within MAPDL. +APDL isn't going anywhere. In fact, whenever you call Mechanical Workbench, it's +generating an input file (``ds.dat``) that's fed into MAPDL. However, what's +changed over the past several years is where the geometry, meshing, and +postprocessing is occurring. Geometry generation can take place within +SpaceClaim or Design Modeler, and meshing is done using a variety of new and +powerful meshers within Workbench. While these tools are far superior to the +ones in MAPDL, their biggest limitation is that they're difficult to script +(especially externally). As a result, there are still users who choose to +generate the geometry and mesh within MAPDL. What are the main reasons to use PyMAPDL over other Ansys products like Workbench? diff --git a/doc/source/getting_started/index.rst b/doc/source/getting_started/index.rst index 75d5f6cfda..5936e3dbd9 100644 --- a/doc/source/getting_started/index.rst +++ b/doc/source/getting_started/index.rst @@ -1,122 +1,30 @@ -=============== -Getting started -=============== -To use PyMAPDL, you must have a local installation of Ansys. The -version of Ansys installed dictates the interface and features -available to you. - -For more information on getting a licensed copy of Ansys, visit -`Ansys `_. .. toctree:: :hidden: :maxdepth: 3 + install_mapdl + install_pymapdl + launcher learning + contribution + faq versioning - running_mapdl docker macos wsl using_julia - faq - contribution make_container_link devcontainer_link -.. _installation: - -************ -Installation -************ - -Python module -~~~~~~~~~~~~~ -The ``ansys.mapdl.core`` package currently supports Python 3.8 through -Python 3.12 on Windows, Mac OS, and Linux. - -Install the latest release from -`PyPi `_ with: - -.. code:: console - - pip install ansys-mapdl-core - -Alternatively, install the latest from -`PyMAPDL GitHub `_ via: - -.. code:: console - - pip install git+https://github.com/ansys/pymapdl.git - - -For a local *development* version, install with: - -.. code:: console - - git clone https://github.com/ansys/pymapdl.git - cd pymapdl - pip install -e . - -This allows you to install the ``ansys-mapdl-core`` module -and modify it locally and have the changes reflected in your setup -after restarting the Python kernel. - - -Offline installation -~~~~~~~~~~~~~~~~~~~~ -If you lack an internet connection on your install machine, the recommended way -of installing PyMAPDL is downloading the wheelhouse archive from the -`Releases Page `_ for your corresponding -machine architecture. - -Each wheelhouse archive contains all the Python wheels necessary to install -PyMAPDL from scratch on Windows and Linux for Python 3.8 and 3.9. You can install -this on an isolated system with a fresh Python or on a virtual environment. - -For example, on Linux with Python 3.8, unzip it and install it with the following: - -.. code:: console - - unzip PyMAPDL-v0.62.dev1-wheelhouse-Linux-3.8.zip wheelhouse - pip install ansys-mapdl-core -f wheelhouse --no-index --upgrade --ignore-installed - -If you're on Windows with Python 3.9, unzip to a ``wheelhouse`` directory and -install using the preceding command. - -Consider installing using a `virtual environment `_. - - -Ansys software requirements -~~~~~~~~~~~~~~~~~~~~~~~~~~~ -For the latest features, you must have a copy of Ansys 2021 R1 -installed locally. However, PyMAPDL is compatible with Ansys 17.0 and later -on Windows and with Ansys 13.0 on Linux. - -.. note:: - - The latest versions of Ansys provide significantly better support - and features. Certain features are not supported on earlier - Ansys versions. - -For more information, see :ref:`install_mapdl`. - -Verify your installation -~~~~~~~~~~~~~~~~~~~~~~~~ -Check that you can start MAPDL from Python by running: - -.. code:: pycon - - >>> from ansys.mapdl.core import launch_mapdl - >>> mapdl = launch_mapdl() - >>> print(mapdl) +=============== +Getting started +=============== - Product: ANSYS Mechanical Enterprise - MAPDL Version: RELEASE 2021 R1 BUILD 21.0 - PyMAPDL Version: Version: 0.58.0 +To use PyMAPDL you must follow the next three steps: -If you see a response from the server, congratulations. You're ready -to get started using MAPDL as a service. For information on the -PyMAPDL interface, see :ref:`ref_mapdl_user_guide`. +* :ref:`ref_using_standard_install` +* :ref:`ref_pymapdl_installation` +* :ref:`ref_launch_pymapdl` diff --git a/doc/source/getting_started/install_mapdl.rst b/doc/source/getting_started/install_mapdl.rst new file mode 100644 index 0000000000..49a0d56579 --- /dev/null +++ b/doc/source/getting_started/install_mapdl.rst @@ -0,0 +1,56 @@ + + +.. _ref_using_standard_install: install_mapdl_ + +.. _install_mapdl: + +************* +Install MAPDL +************* + + +The PyAnsys ``ansys-mapdl-core`` package (PyMAPDL) requires either a local or +remote instance of MAPDL to communicate with it. This section covers +launching and interfacing with MAPDL from a local instance by +launching it from Python. + +MAPDL is installed by default from the Ansys standard installer. When +installing Ansys, verify that the **Mechanical Products** checkbox is +selected under the **Structural Mechanics** option. While the standard +installer options can change, see the following figure for reference. + +.. figure:: ../images/unified_install_2019R1.jpg + :width: 400pt + + +If you want to avoid having to install MAPDL locally, you can use Docker. +This is especially convenient if you are using a non-supported platform such +as MacOS. +For more information, see :ref:`ref_pymapdl_and_macos`. + +You can also download and try the `Ansys Student Version `_. +A Student Version is valid during a calendar year with limited capabilities. For +example, there is a limit on the number of nodes and elements. + +If you experience problems installing MAPDL on Linux, see +:ref:`missing_dependencies_on_linux`. + + +Ansys software requirements +--------------------------- + +For the latest features, you must have a copy of Ansys 2021 R1 or later +installed locally. However, PyMAPDL is compatible with Ansys 17.0 and later +on Windows and with Ansys 13.0 on Linux. However, its usage with these older +versions is discouraged. + +.. note:: + + The latest versions of Ansys provide significantly better support + and features. Certain features are not supported on earlier + Ansys versions. + +For more information, see :ref:`versions_and_interfaces`. + + +For information on installing PyMAPDL, see :ref:`ref_pymapdl_installation`. \ No newline at end of file diff --git a/doc/source/getting_started/install_pymapdl.rst b/doc/source/getting_started/install_pymapdl.rst new file mode 100644 index 0000000000..d0b6034e55 --- /dev/null +++ b/doc/source/getting_started/install_pymapdl.rst @@ -0,0 +1,84 @@ + + +.. _ref_pymapdl_installation: + +*************** +Install PyMAPDL +*************** + +Python module +~~~~~~~~~~~~~ +The ``ansys.mapdl.core`` package currently supports Python 3.8 through +Python 3.11 on Windows, Mac OS, and Linux. + +Install the latest release from `PyPi `_ with: + +.. code:: console + + pip install ansys-mapdl-core + +Alternatively, install the latest from +`PyMAPDL GitHub `_ with this command: + +.. code:: console + + pip install git+https://github.com/ansys/pymapdl.git + + +For a local *development* version, install with these commands: + +.. code:: console + + git clone https://github.com/ansys/pymapdl.git + cd pymapdl + pip install -e . + +After installing a development version, you can modify the ``ansys-mapdl-core`` package +locally and have the changes reflected in your setup after restarting the Python kernel. + + +Offline installation +~~~~~~~~~~~~~~~~~~~~ +If you lack an internet connection on your installation machine, the recommended way +of installing PyMAPDL is downloading the wheelhouse archive from the +`Releases `_ page for your corresponding +machine architecture. + +Each wheelhouse archive contains all the Python wheels necessary to install +PyMAPDL from scratch on Windows and Linux. You can install +this on an isolated system with a fresh Python installation or on a virtual environment. + +For example, on Linux with Python 3.9, unzip the wheelhouse archive and install it with +these commands: + +.. code:: console + + unzip PyMAPDL-v0.68.dev1-wheelhouse-Linux-3.9.zip wheelhouse + pip install ansys-mapdl-core -f wheelhouse --no-index --upgrade --ignore-installed + +If you're on Windows with Python 3.9, unzip to a ``wheelhouse`` directory and +install using the preceding command. + +Consider installing using a `virtual environment `_. + +Verify your installation +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + To use PyMAPDL, you must have a local installation of Ansys. The + version of Ansys installed dictates the interface and features + available to you. + + For more information on getting a licensed copy of Ansys, visit + `Ansys `_. + + +Check that you have installed the package correctly by importing the module: + +.. code:: pycon + + >>> from ansys.mapdl import core as pymapdl + + +For information on launching PyMAPDL and connecting it +to an MAPDL instance, see:ref:`ref_launch_pymapdl`. diff --git a/doc/source/getting_started/launcher.rst b/doc/source/getting_started/launcher.rst new file mode 100644 index 0000000000..df173b2433 --- /dev/null +++ b/doc/source/getting_started/launcher.rst @@ -0,0 +1,235 @@ + + +.. _ref_launch_pymapdl: + + +Launch PyMAPDL +============== + +PyMAPDL can start MAPDL locally, or it can connect to a session already running locally or +on a remote machine. + +* `Launch PyMAPDL with a local MAPDL instance`_ +* `Connect PyMAPDL to a local MAPDL instance`_ +* `Connect PyMAPDL to a remote MAPDL instance`_ + +If you have any problem launching PyMAPDL, see :ref:`Launching issues `. + + +Launch PyMAPDL with a local MAPDL instance +------------------------------------------ + +You can use the :func:`launch_mapdl() ` +function to start MAPDL and automatically connect to it: + +.. code:: pycon + + >>> from ansys.mapdl.core import launch_mapdl + >>> mapdl = launch_mapdl() + >>> print(mapdl) + Product: Ansys Mechanical Enterprise + MAPDL Version: 24.1 + ansys.mapdl Version: 0.68.0 + + +While this is the easiest and fastest way to get PyMAPDL up and running. +you must be able to launch MAPDL locally. + +If PyMAPDL cannot find your local installation, see +`Setting the MAPDL location in PyMAPDL`_. + +For more information on controlling how MAPDL launches locally, see the +description of the :func:`launch_mapdl() ` function. + + +Connect PyMAPDL to a local MAPDL instance +----------------------------------------- + +Connect to a local MAPDL instance requires two steps: launching a +local MAPDL session and connect to it. + +.. _launch_grpc_madpl_session: + +Launch a local gRPC MAPDL session +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can start MAPDL from the command line and then connect to it. + +To launch MAPDL on Windows (assuming that Ansys is installed in the +:file:`C:/Program Files/ANSYS Inc/v241` directory), use this command: + +.. code:: pwsh-session + + C:/Program Files/ANSYS Inc/v241/ansys/bin/winx64/ANSYS211.exe -grpc + +To launch MAPDL on Linux (assuming that Ansys is installed in the +:file:`/usr/ansys_inc` directory), use this command: + +.. code:: console + + /usr/ansys_inc/v241/ansys/bin/ansys211 -grpc + +This starts MAPDL in gRPC mode. MAPDL should display this output: + +.. code:: output + + Start GRPC Server + + ############################## + ### START GRPC SERVER ### + ############################## + + Server Executable : MapdlGrpc Server + Server listening on : 0.0.0.0:50052 + +You can configure the port that MAPDL starts on with the ``-port`` argument. +For example, you can start the server to listen for connections at +port 50005 with this command: + +.. code:: console + + /usr/ansys_inc/v241/ansys/bin/ansys211 -port 50005 -grpc + + +.. _connect_grpc_madpl_session: + +Connect to the local MAPDL instance +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +An MAPDL gRPC server can be connected to from the same host by using +this code: + +.. code:: pycon + + >>> from ansys.mapdl.core import Mapdl + >>> mapdl = Mapdl() + +The preceding code assumes that your MAPDL service is running locally on the default IP address +(``127.0.0.1``) and on the default port (``50052``). + +You can also use the :func:`launch_mapdl() ` method to connect to an already launched MAPDL instance by setting the ``start_instance`` argument to ``False``: + +.. code:: pycon + + >>> from ansys.mapdl.core import launch_mapdl + >>> mapdl = launch_mapdl(start_instance=False) + +If you are connecting to an MAPDL Docker image, the procedure is the same. +Just make sure that you specify the mapped port instead of the internal MAPDL port. +For more information, see :ref:`pymapdl_docker`. + + +.. _connect_grpc_remote_madpl_session: + +Connect PyMAPDL to a remote MAPDL instance +------------------------------------------ + +If you want to connect to a **remote** MAPDL instance, you must know the IP +address of that instance. +For example, if on your local network at IP address ``192.168.0.1`` there is a +computer running MAPDL on the port ``50052``, you can connect to it with this code: + +.. code:: pycon + + >>> mapdl = Mapdl("192.168.0.1", port=50052) + +Alternatively, you can use a hostname: + +.. code:: pycon + + >>> mapdl = Mapdl("myremotemachine", port=50052) + +Note that you must have started an MAPDL instance in gRPC mode on the computer with +the referenced IP address and hostname for this to work because PyMAPDL cannot launch remote instances. + + +Setting the MAPDL location in PyMAPDL +------------------------------------- + +To run, PyMAPDL must know the location of the MAPDL binary. +Most of the time this can be automatically determined, but +the location of MAPDL must be provided for non-standard installations. +When running for the first time, PyMAPDL requests the +location of the MAPDL executable if it cannot automatically find it. + +You can test your installation of PyMAPDL and set it up by running +the :func:`launch_mapdl() ` function: + +.. code:: python + + from ansys.mapdl.core import launch_mapdl + + mapdl = launch_mapdl() + +Python automatically attempts to detect your MAPDL binary based on +environmental variables. +You can specify an MAPDL installation using one of two environment +variables: + +* ``AWP_ROOTXXX``, where ``XXX``` is the three-digit version. This environment variable + contains the path of the Ansys installation with the version matching ``XXX``. + For example, ``AWP_ROOT222=/ansys_inc`` contains the path to an Ansys 2022 R2 installation. + +* ``PYMAPDL_MAPDL_EXEC`` contains the path to the Ansys MAPDL executable file. + For example, ``PYMAPDL_MAPDL_EXEC=/ansys_inc/v222/ansys/bin/ansys222``. + +If PyMAPDL is unable to find a copy of MAPDL, you +are prompted for the location of the MAPDL executable. + +Here is the prompt with an example response for Windows: + +.. code:: output + + Enter location of MAPDL executable: C:\Program Files\ANSYS Inc\v222\ANSYS\bin\winx64\ansys222.exe + +Here is the prompt with an example response for Linux: + +.. code:: output + + Enter location of MAPDL executable: /usr/ansys_inc/v222/ansys/bin/ansys222 + +The settings file is stored locally, which means that you are not prompted +to enter the path again. If you must change the default Ansys path +(meaning change the default version of MAPDL), run this code: + +.. code:: python + + from ansys.mapdl import core as pymapdl + + new_path = "C:\\Program Files\\ANSYS Inc\\v212\\ANSYS\\bin\\winx64\\ansys222.exe" + pymapdl.change_default_ansys_path(new_path) + +For more information, see the :func:`change_default_ansys_path() ` method and the :func:`find_ansys() ` method. + +Additionally, it is possible to specify the executable in each PyMAPDL script using the ``exec_file`` keyword argument. + + +**On Windows:** + +.. code:: python + + from ansys.mapdl.core import launch_mapdl + + mapdl = launch_mapdl( + exec_file="C://Program Files//ANSYS Inc//v212//ANSYS//bin//winx64//ansys212.exe" + ) + +**On Linux:** + +.. code:: python + + from ansys.mapdl.core import launch_mapdl + + mapdl = launch_mapdl(exec_file="/usr/ansys_inc/v212/ansys/bin/ansys212") + + +You could also specify a custom executable made from a custom MAPDL compilation by adding the correspondent flag (``-custom``) to the ``additional_switches`` +keyword argument: + +.. code:: python + + from ansys.mapdl.core import launch_mapdl + + custom_exec = "/usr/ansys_inc/v212/ansys/bin/ansys212t" + add_switch = f" -custom {custom_exec}" + mapdl = launch_mapdl(additional_switches=add_switch) diff --git a/doc/source/getting_started/running_mapdl.rst b/doc/source/getting_started/running_mapdl.rst deleted file mode 100644 index 2603c73f2d..0000000000 --- a/doc/source/getting_started/running_mapdl.rst +++ /dev/null @@ -1,145 +0,0 @@ -.. _using_standard_install: - -********************* -Standard installation -********************* - -The PyAnsys ``ansys-mapdl-core`` package requires either a local or -remote instance of MAPDL to communicate with it. This section covers -launching and interfacing with MAPDL from a local instance by -launching it from Python. - - -.. _install_mapdl: - -Install MAPDL -------------- - -MAPDL is installed by default from the Ansys standard installer. When -installing Ansys, verify that the **Mechanical Products** checkbox is -selected under the **Structural Mechanics** option. While the standard -installer options can change, see the following figure for reference. - -.. figure:: ../images/unified_install_2019R1.jpg - :width: 400pt - - -If you want to avoid having to install MAPDL locally, you can use Docker. -This is especially convenient if you are using a non-supported platform such -as MacOS. -For more information, see :ref:`ref_pymapdl_and_macos`. - -You can also download and try the `Ansys Student Versions `_. -A Student Version is valid during a calendar year with limited capabilities. For -example, there is a limit on the number of nodes and elements. - -If you experience problems installing MAPDL on Linux, see -:ref:`missing_dependencies_on_linux`. - -Launch MAPDL ------------- - -Launch MAPDL locally -~~~~~~~~~~~~~~~~~~~~ - -You can use the :func:`launch_mapdl() ` method to have Python start MAPDL and -automatically connect to it: - -.. code:: pycon - - >>> from ansys.mapdl.core import launch_mapdl - >>> mapdl = launch_mapdl() - >>> print(mapdl) - - Product: ANSYS Mechanical Enterprise - MAPDL Version: RELEASE 2021 R1 BUILD 21.0 - PyMAPDL Version: Version: 0.57.0 - - -This is the easiest and fastest way to get PyMAPDL up and running. -But you need to have an ANSYS license server installed locally. - -.. _launch_grpc_madpl_session: - -Launch a gRPC MAPDL session -~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can start MAPDL from the command line and then connect to it. - -To launch MAPDL on Windows (assuming a :file:`C:/Program Files/ANSYS Inc/v211` installation), use: - -.. code:: pwsh-session - - C:/Program Files/ANSYS Inc/v211/ansys/bin/winx64/ANSYS211.exe -grpc - -To launch MAPDL on Linux (assuming a :file:`/usr/ansys_inc` installation), use: - -.. code:: console - - /usr/ansys_inc/v211/ansys/bin/ansys211 -grpc - -This starts up MAPDL in gRPC mode, and MAPDL should output: - -.. code:: output - - Start GRPC Server - - ############################## - ### START GRPC SERVER ### - ############################## - - Server Executable : MapdlGrpc Server - Server listening on : 0.0.0.0:50052 - -You can configure the port that MAPDL starts on with the ``-port`` argument. -For example, you can start the server to listen for connections at -port 50005 with: - -.. code:: console - - /usr/ansys_inc/v211/ansys/bin/ansys211 -port 50005 -grpc - - -.. _connect_grpc_madpl_session: - -Connect to a gRPC MAPDL session -------------------------------- - -A MAPDL gRPC server can be connected to from either the same host or an -external host. For example, you can connect to a MAPDL service -running **locally** with: - -.. code:: pycon - - >>> from ansys.mapdl.core import Mapdl - >>> mapdl = Mapdl() - - -This assumes that your MAPDL service is running locally on the default IP address -(``127.0.0.1``) and on the default port (``50052``). - -If you want to connect to a **remote** instance of MAPDL and you know the IP -address of that instance, you can connect to it. -For example, if on your local network at IP address ``192.168.0.1`` there is a -computer running MAPDL on the port 50052, you can connect to it with: - -.. code:: pycon - - >>> mapdl = Mapdl("192.168.0.1", port=50052) - -Alternatively you can use a hostname: - -.. code:: pycon - - >>> mapdl = Mapdl("myremotemachine", port=50052) - -Note that you must have started MAPDL in gRPC mode on the computer with -the mentioned IP address/hostname for this to work. - -If you have MAPDL installed on your local host, you -can use the :func:`launch_mapdl() ` method to both start and connect to MAPDL. - -If you have any problem launching PyMAPDL, see :ref:`Launching issues `. - -If you are connecting to an MAPDL Docker image, the procedure is the same. -Just make sure that you specify the mapped port instead of the internal Docker image port. -For more information, see :ref:`pymapdl_docker`. diff --git a/doc/source/getting_started/using_julia.rst b/doc/source/getting_started/using_julia.rst index 659cef73c5..bdb8c7bffd 100644 --- a/doc/source/getting_started/using_julia.rst +++ b/doc/source/getting_started/using_julia.rst @@ -122,8 +122,8 @@ Finally, after restarting Julia, you can import PyMAPDL using the same procedure julia> mapdl = pymapdl.launch_mapdl() julia> print(mapdl.__str__()) Product: Ansys Mechanical Enterprise - MAPDL Version: 21.2 - ansys.mapdl Version: 0.60.6 + MAPDL Version: 24.1 + ansys.mapdl Version: 0.68.0 .. note:: If you experience errors when using PyCall, you can try to rebuild the package by pressing ``"]"`` to go to the package manager and typing: diff --git a/doc/source/index.rst b/doc/source/index.rst index fe5c6ff1c9..9cf5c570ec 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -74,10 +74,9 @@ Here's a brief example of how PyMAPDL works: >>> from ansys.mapdl.core import launch_mapdl >>> mapdl = launch_mapdl() >>> print(mapdl) - - Product: ANSYS Mechanical Enterprise - MAPDL Version: RELEASE 2021 R1 BUILD 21.0 - PyMAPDL Version: Version: 0.57.0 + Product: Ansys Mechanical Enterprise + MAPDL Version: 24.1 + ansys.mapdl Version: 0.68.0 MAPDL is now active and you can send commands to it as a genuine Python class. For example, if you wanted to create a surface using diff --git a/doc/source/links.rst b/doc/source/links.rst index a4a445b702..b1fb34392a 100644 --- a/doc/source/links.rst +++ b/doc/source/links.rst @@ -148,10 +148,10 @@ .. _pymapdl_discussion_differences_mapdl_pymapdl: https://github.com/ansys/pymapdl-reader/issues/185 .. _cartpole_example_notebook: https://cartpole.mapdl.docs.pyansys.com/ml-rl-notebook.html .. _wsl_launching_mapdl: https://github.com/ansys/pymapdl/issues/2315 +.. _pymapdl_search_issues_pr: https://github.com/ansys/pymapdl/issues?q= .. _pymapdl_latest_github_release: https://github.com/ansys/pymapdl/releases/latest .. _pymapdl_latest_pdf_doc: https://github.com/ansys/pymapdl/releases/download/v%%PYMAPDLVERSION%%.0/pymapdl-Documentation-%%PYMAPDLVERSION%%.0.pdf - .. #Python .. _using_venv: https://docs.python.org/3/library/venv.html .. _conda: https://conda.io diff --git a/doc/source/user_guide/index.rst b/doc/source/user_guide/index.rst index ca2df903cb..9d4c4536da 100644 --- a/doc/source/user_guide/index.rst +++ b/doc/source/user_guide/index.rst @@ -14,16 +14,15 @@ This section provides a general overview of PyMAPDL and how you use it. :maxdepth: 1 :hidden: - launcher mapdl - mapdl_examples - plotting + convert mesh_geometry - post + plotting parameters components + post + mapdl_examples database - convert math pool xpl @@ -34,18 +33,18 @@ This section provides a general overview of PyMAPDL and how you use it. PyMAPDL overview ================ -The :func:`launch_mapdl() ` function +The :func:`launch_mapdl() ` function within the ``ansys-mapdl-core`` library creates an instance of the :class:`Mapdl ` class in the background and sends -commands to that service. Errors and warnings are processed +commands to that instance. Errors and warnings are processed Pythonically, letting you develop a script in real time, without worrying about it functioning correctly when deployed in batch mode. MAPDL can be started from Python in gRPC mode using the -:func:`launch_mapdl() ` method. This starts +:func:`launch_mapdl() ` method. This starts MAPDL in a temporary directory by default. You can change this to -your current directory with: +your current directory with this code: .. code:: python @@ -55,7 +54,7 @@ your current directory with: path = os.getcwd() mapdl = launch_mapdl(run_location=path) -MAPDL is now active, and you can send commands to it as a genuine a +MAPDL is now active, and you can send commands to it as a genuine Python class. For example, if you wanted to create a surface using key points, you could run: @@ -132,16 +131,16 @@ Additionally, exceptions are caught and handled within Python. >>> mapdl.run("AL, 1, 2, 3") - xception: - L, 1, 2, 3 + Exception: + AL, 1, 2, 3 - EFINE AREA BY LIST OF LINES - INE LIST = 1 2 3 - TRAVERSED IN SAME DIRECTION AS LINE 1) + DEFINE AREA BY LIST OF LINES + LINE LIST = 1 2 3 + (TRAVERSED IN SAME DIRECTION AS LINE 1) - ** ERROR *** CP = 0.338 TIME= 09:45:36 - eypoint 1 is referenced by only one line. Improperly connected line - et for AL command. + *** ERROR *** CP = 0.338 TIME= 09:45:36 + Keypoint 1 is referenced by only one line. Improperly connected line + set for AL command. For longer scripts, instead of sending commands to MAPDL as in the diff --git a/doc/source/user_guide/launcher.rst b/doc/source/user_guide/launcher.rst deleted file mode 100644 index cfc3c61941..0000000000 --- a/doc/source/user_guide/launcher.rst +++ /dev/null @@ -1,84 +0,0 @@ -Initial setup and launch of MAPDL locally ------------------------------------------ -To run, ``ansys.mapdl.core`` must know the location of the MAPDL -binary. Most of the time this can be automatically determined, but -the location of MAPDL must be provided for non-standard installations. -When running for the first time, ``ansys-mapdl-core`` requests the -location of the MAPDL executable if it cannot automatically find it. -You can test your installation of PyMAPDL and set it up by running -the :func:`launch_mapdl() ` function: - -.. code:: python - - from ansys.mapdl.core import launch_mapdl - - mapdl = launch_mapdl() - -Python automatically attempts to detect your MAPDL binary based on -environmental variables. If it is unable to find a copy of MAPDL, you -are prompted for the location of the MAPDL executable. - -Here is a sample input for Linux: - -.. code:: output - - Enter location of MAPDL executable: /usr/ansys_inc/v222/ansys/bin/ansys222 - -Here is a sample input for Windows: - -.. code:: output - - Enter location of MAPDL executable: C:\Program Files\ANSYS Inc\v222\ANSYS\bin\winx64\ansys222.exe - -The settings file is stored locally, which means that you are not prompted -to enter the path again. If you must change the default Ansys path -(meaning change the default version of MAPDL), run the following: - -.. code:: python - - from ansys.mapdl import core as pymapdl - - new_path = "C:\\Program Files\\ANSYS Inc\\v212\\ANSYS\\bin\\winx64\\ansys222.exe" - pymapdl.change_default_ansys_path(new_path) - -Also see the :func:`change_default_ansys_path() ` method and -the :func:`find_ansys() ` method. - -Additionally, it is possible to specify the executable using the keyword argument ``exec_file``. - -In Linux: - -.. code:: python - - from ansys.mapdl.core import launch_mapdl - - mapdl = launch_mapdl(exec_file="/usr/ansys_inc/v212/ansys/bin/ansys212") - - -In Windows: - -.. code:: python - - from ansys.mapdl.core import launch_mapdl - - mapdl = launch_mapdl( - exec_file="C://Program Files//ANSYS Inc//v212//ANSYS//bin//winx64//ansys212.exe" - ) - -You could also specify a custom executable by adding the correspondent flag (``-custom``) to the ``additional_switches`` -keyword argument: - -.. code:: python - - from ansys.mapdl.core import launch_mapdl - - custom_exec = "/usr/ansys_inc/v212/ansys/bin/ansys212t" - add_switch = f" -custom {custom_exec}" - mapdl = launch_mapdl(additional_switches=add_switch) - - - -API reference -~~~~~~~~~~~~~ -For more information on controlling how MAPDL launches locally, see the -description of the :func:`launch_mapdl() ` function. diff --git a/doc/source/user_guide/mapdl.rst b/doc/source/user_guide/mapdl.rst index bfaa5dc813..07e7fa7c73 100644 --- a/doc/source/user_guide/mapdl.rst +++ b/doc/source/user_guide/mapdl.rst @@ -896,7 +896,7 @@ These are described in the following table: +---------------------------------------+---------------------------------------------------------------------+ | :envvar:`PYMAPDL_START_INSTANCE` | Override the behavior of the | -| | :func:`ansys.mapdl.core.launch_mapdl` function | +| | :func:`ansys.mapdl.core.launcher.launch_mapdl` function | | | to only attempt to connect to existing | | | instances of PyMAPDL. Generally used | | | in combination with ``PYMAPDL_PORT``. | diff --git a/doc/source/user_guide/troubleshoot.rst b/doc/source/user_guide/troubleshoot.rst index 13610d5bad..b007e0d9b0 100644 --- a/doc/source/user_guide/troubleshoot.rst +++ b/doc/source/user_guide/troubleshoot.rst @@ -55,21 +55,22 @@ There are several issues that can cause MAPDL not to launch, including: - `Using a proxy server`_ - `Firewall settings`_ +If you cannot find your issue, see `More help needed?`_. + Connection timeout ~~~~~~~~~~~~~~~~~~ In some networks, MAPDL might take longer than expected to connect to the license server or to the remote instance. -In those cases, you might see the following message: +In those cases, you might see this message: -.. vale off -.. rubric:: PyMAPDL is taking longer than expected to connect to an MAPDL session. Checking if there are any available licenses... +.. code:: output -.. vale on + PyMAPDL is taking longer than expected to connect to an MAPDL session. Checking if there are any available licenses... -You might consider to increase the starting timeout before trying other options. -The start timeout can be increased using: + +First try increasing the starting timeout using this code: .. code:: python @@ -380,7 +381,7 @@ When `gRPC `_ is used in a proxy environment, if a local address is speci as the connection destination, the gRPC implementation refers automatically to the proxy address. In this case, the local address cannot be referred, resulting in a connection error. As a workaround, you can set the environment variable ``NO_PROXY`` to your local address ``127.0.0.1``, -and then run :func:`launch_mapdl() ` +and then run :func:`launch_mapdl() ` to connect to MAPDL instance. @@ -420,7 +421,8 @@ Manually set the location of the executable file If you have a non-standard install, PyMAPDL might be unable find your MAPDL installation. If this is the case, provide the location of MAPDL -as the first parameter to :func:`launch_mapdl() `. +as the first parameter to the :func:`launch_mapdl() ` +method. **On Windows** @@ -454,7 +456,9 @@ Ansys installations are normally under: C:/Program Files/ANSYS Inc/vXXX + **On Linux** + Ansys installations are normally under: .. code:: text @@ -594,36 +598,38 @@ your program or script so that you can turn on and off logging and verbosity as needed. -Issues -~~~~~~ +Known Issues +~~~~~~~~~~~~ -.. note:: - - MAPDL 2021 R1 has a stability issue with the : - :func:`Mapdl.input() ` - method. Avoid using input files if possible. Attempt to use the - :func:`Mapdl.upload() ` method to upload - nodes and elements and read them in via the - :func:`Mapdl.nread() ` and - :func:`Mapdl.eread() ` methods. +* MAPDL 2021 R1 has a stability issue with the : + :func:`Mapdl.input() ` + method. Avoid using input files if possible. Attempt to use the + :func:`Mapdl.upload() ` method to upload + nodes and elements and read them in via the + :func:`Mapdl.nread() ` and + :func:`Mapdl.eread() ` methods. More help needed? ----------------- +.. vale off + .. epigraph:: - *"What do you do if a problem is not listed here?"* + *"What do I do if an issue is not listed here?"* + +.. vale on +To see if your issue is already posted, search the `PyMAPDL Issues `_ page. If not, do one of the following: -Go to the `PyMAPDL Issues `_ page and search to see if your -issue is already listed. If not, you can do one of the following: +* If you are not sure of the cause or would like some explanation about the + usage of the function or its documentation, create a discussion on the + `PyMAPDL Discussions `_ page. -* Go to the `PyMAPDL Discussions `_ page and - create a discussion about your issue. -* Go to the `PyMAPDL Issues `_ if you have found a bug - or want to create a feature request. +* If you believe you have found a bug or want to create a feature request, + create an issue on the `PyMAPDL Issues `_ page. -For more complex issues or queries, contact `PyAnsys Core team `_. +For more complex issues or queries, contact the `PyAnsys Core team `_. diff --git a/examples/00-mapdl-examples/lathe_cutter.py b/examples/00-mapdl-examples/lathe_cutter.py index d0c7cb1f3a..935e3139ac 100644 --- a/examples/00-mapdl-examples/lathe_cutter.py +++ b/examples/00-mapdl-examples/lathe_cutter.py @@ -81,7 +81,7 @@ ############################################################################### # Often used MAPDL command line options are exposed as Pythonic parameter names in -# :func:`ansys.mapdl.core.launch_mapdl`. For example, ``-dir`` +# :func:`ansys.mapdl.core.launcher.launch_mapdl`. For example, ``-dir`` # has become ``run_location``. # You could use ``run_location`` to specify the MAPDL run location. For example: # @@ -326,7 +326,7 @@ ############################################################################### # Get the principal nodal stresses of the node subset. -mapdl.nsel("S", "S", 1, 6700, 7720) +mapdl.nsel("S", vmin=1200, vmax=1210) mapdl.esln() mapdl.nsle() diff --git a/src/ansys/mapdl/core/misc.py b/src/ansys/mapdl/core/misc.py index c2fa1b0f2c..94268eca81 100644 --- a/src/ansys/mapdl/core/misc.py +++ b/src/ansys/mapdl/core/misc.py @@ -697,13 +697,13 @@ class Information: -------- >>> mapdl.info Product: Ansys Mechanical Enterprise - MAPDL Version: 21.2 - ansys.mapdl Version: 0.62.dev0 + MAPDL Version: 24.1 + ansys.mapdl Version: 0.68.0 >>> print(mapdl) Product: Ansys Mechanical Enterprise - MAPDL Version: 21.2 - ansys.mapdl Version: 0.62.dev0 + MAPDL Version: 24.1 + ansys.mapdl Version: 0.68.0 >>> mapdl.info.product 'Ansys Mechanical Enterprise' diff --git a/src/ansys/mapdl/core/pool.py b/src/ansys/mapdl/core/pool.py index 4a3b51f87c..e8eb9a3681 100755 --- a/src/ansys/mapdl/core/pool.py +++ b/src/ansys/mapdl/core/pool.py @@ -93,8 +93,8 @@ class LocalMapdlPool: By default, the instances directories are named as "Instances_{i}". **kwargs : dict, optional - See :func:`ansys.mapdl.core.launch_mapdl` for a complete - listing of all additional keyword arguments. + Additional keyword arguments. For a complete listing, see the description for the + :func:`ansys.mapdl.core.launcher.launch_mapdl` method. Examples -------- @@ -557,9 +557,9 @@ def next_available(self, return_index=False): -------- >>> mapdl = pool.next_available() >>> print(mapdl) - Product: ANSYS Mechanical Enterprise - MAPDL Version: RELEASE BUILD 0.0 UPDATE 0 - PyANSYS Version: 0.55.1 + Product: Ansys Mechanical Enterprise + MAPDL Version: 24.1 + ansys.mapdl Version: 0.68.dev0 """ # loop until the next instance is available From 757364a62148a50c56fca98d205d754c80f14a1a Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Tue, 21 Nov 2023 12:00:04 +0100 Subject: [PATCH 22/30] Allowing latest as version (#2515) * Allowing latest as version * Adding test * version checking after PIM launcher --------- Co-authored-by: Camille <78221213+clatapie@users.noreply.github.com> --- src/ansys/mapdl/core/launcher.py | 9 ++++++--- tests/test_launcher.py | 4 ++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/ansys/mapdl/core/launcher.py b/src/ansys/mapdl/core/launcher.py index 9a23856417..ff1620e2ab 100644 --- a/src/ansys/mapdl/core/launcher.py +++ b/src/ansys/mapdl/core/launcher.py @@ -1435,8 +1435,6 @@ def launch_mapdl( if version is None: version = os.getenv("PYMAPDL_MAPDL_VERSION", None) - version = _verify_version(version) # return a int version or none - # Start MAPDL with PyPIM if the environment is configured for it # and the user did not pass a directive on how to launch it. if _HAS_PIM and exec_file is None and pypim.is_configured(): @@ -1448,6 +1446,8 @@ def launch_mapdl( return launch_remote_mapdl(cleanup_on_exit=cleanup_on_exit, version=version) + version = _verify_version(version) # return a int version or none + # connect to an existing instance if enabled if start_instance is None: if "PYMAPDL_START_INSTANCE" in os.environ: @@ -1882,7 +1882,10 @@ def _verify_version(version): version = int(version * 10) if isinstance(version, str): - if version.upper().strip() in [ + if version.lower().strip() == "latest": + return None # Default behaviour is latest + + elif version.upper().strip() in [ str(each) for each in SUPPORTED_ANSYS_VERSIONS.keys() ]: version = int(version) diff --git a/tests/test_launcher.py b/tests/test_launcher.py index 13c414f683..11c055ca60 100644 --- a/tests/test_launcher.py +++ b/tests/test_launcher.py @@ -400,6 +400,10 @@ def test__verify_version_pass(version): assert min(versions.keys()) <= ver <= max(versions.keys()) +def test__verify_version_latest(): + assert _verify_version("latest") is None + + @requires("ansys-tools-path") @requires("local") def test_find_ansys(mapdl): From 94320a623b93f883a0fd2a1917882660cca1b06f Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Tue, 21 Nov 2023 12:00:46 +0100 Subject: [PATCH 23/30] Moving functions to Mapdl class (#2468) * Moving parres and inquire * Moving lgwrite * Moving VWRITE * Moving *USE * Moving NRM * Moving /COM * Moving LSSOLVE * fixing typo * Disabling Google heading. Adding `mapdl` (lowercase) to accepts. Fixing other warnings. * fixing vale version to avoid pipeline unexpected breakdowns. * Undoing changes from main * Empty comment to trigger CICD * Empty commit to re-trigger CICD * Fixing tests * fixing indentation * Fixing com command * Fixing typo --- .../mapdl/core/_commands/apdl/array_param.py | 7 - .../mapdl/core/_commands/apdl/macro_files.py | 5 +- .../mapdl/core/_commands/apdl/matrix_op.py | 5 +- .../_commands/apdl/parameter_definition.py | 86 +------- .../mapdl/core/_commands/session/files.py | 31 +-- .../core/_commands/session/list_controls.py | 4 +- .../solution/load_step_operations.py | 4 +- src/ansys/mapdl/core/mapdl.py | 188 +++++++++++++++++- src/ansys/mapdl/core/misc.py | 2 +- tests/test_mapdl.py | 71 ++++++- 10 files changed, 264 insertions(+), 139 deletions(-) diff --git a/src/ansys/mapdl/core/_commands/apdl/array_param.py b/src/ansys/mapdl/core/_commands/apdl/array_param.py index 8c3ee71089..248d1831b0 100644 --- a/src/ansys/mapdl/core/_commands/apdl/array_param.py +++ b/src/ansys/mapdl/core/_commands/apdl/array_param.py @@ -1479,12 +1479,5 @@ def vwrite( This command is valid in any processor. """ - # cannot be in interactive mode - if not self._store_commands: - raise MapdlRuntimeError( - "VWRTIE cannot run interactively. \n\nPlease use " - "``with mapdl.non_interactive:``" - ) - command = f"*VWRITE,{par1},{par2},{par3},{par4},{par5},{par6},{par7},{par8},{par9},{par10},{par11},{par12},{par13},{par14},{par15},{par16},{par17},{par18},{par19}" return self.run(command, **kwargs) diff --git a/src/ansys/mapdl/core/_commands/apdl/macro_files.py b/src/ansys/mapdl/core/_commands/apdl/macro_files.py index 92a427e3c8..961f0a4c75 100644 --- a/src/ansys/mapdl/core/_commands/apdl/macro_files.py +++ b/src/ansys/mapdl/core/_commands/apdl/macro_files.py @@ -565,7 +565,4 @@ def use( This command is valid in any processor. """ command = f"*USE,{name},{arg1},{arg2},{arg3},{arg4},{arg5},{arg6},{arg7},{arg8},{arg9},{ar10},{ar11},{ar12},{ar13},{ar14},{ag15},{ar16},{ar17},{ar18}" - with self.non_interactive: - self.run(command, **kwargs) - - return self._response # returning last response + return self.run(command, **kwargs) diff --git a/src/ansys/mapdl/core/_commands/apdl/matrix_op.py b/src/ansys/mapdl/core/_commands/apdl/matrix_op.py index 3ef2eb317a..18d03f7382 100644 --- a/src/ansys/mapdl/core/_commands/apdl/matrix_op.py +++ b/src/ansys/mapdl/core/_commands/apdl/matrix_op.py @@ -710,11 +710,8 @@ def nrm(self, name="", normtype="", parr="", normalize="", **kwargs): to the L1 norm and is applicable to vectors only. The NRMINF option is the maximum norm and is applicable to either vectors or matrices. """ - if not parr: - parr = "__temp_par__" command = f"*NRM,{name},{normtype},{parr},{normalize}" - self.run(command, **kwargs) - return self.parameters[parr] + return self.run(command, **kwargs) def remove(self, name="", val1="", val2="", val3="", **kwargs): """Suppresses rows or columns of a dense matrix or a vector. diff --git a/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py b/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py index 0504307d11..207fa827f0 100644 --- a/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py +++ b/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py @@ -1,6 +1,3 @@ -import os - - class ParameterDefinition: def afun(self, lab="", **kwargs): """Specifies units for angular functions in parameter expressions. @@ -432,50 +429,7 @@ def inquire(self, strarray="", func="", arg1="", arg2=""): >>> mapdl.inquire('', 'RSTFILE') 'file.rst' """ - func_options = [ - "LOGIN", - "DOCU", - "APDL", - "PROG", - "AUTH", - "USER", - "DIRECTORY", - "JOBNAME", - "RSTDIR", - "RSTFILE", - "RSTEXT", - "OUTPUT", - "ENVNAME", - "TITLE", - "EXIST", - "DATE", - "SIZE", - "WRITE", - "READ", - "EXEC", - "LINES", - ] - - if strarray.upper() in func_options and func.upper() not in func_options: - # Likely you are using the old ``_Mapdl.inquire`` implementation. - raise ValueError( - "Arguments of this method have changed. `Mapdl.inquire` now includes the optional `strarray` parameter " - f"as the first argument. Either use `inquire(func={strarray})`, or `inquire(" - ", {strarray})`" - ) - - if func == "": - func = "DIRECTORY" - - response = self.run(f"/INQUIRE,{strarray},{func},{arg1},{arg2}", mute=False) - if func.upper() in [ - "ENV", - "TITLE", - ]: # the output is multiline, we just need the last line. - response = response.splitlines()[-1] - if "=" in response: - return response.split("=")[1].strip() - return "" + return self.run(f"/INQUIRE,{strarray},{func},{arg1},{arg2}") def parres(self, lab="", fname="", ext="", **kwargs): """Reads parameters from a file. @@ -518,43 +472,7 @@ def parres(self, lab="", fname="", ext="", **kwargs): >>> mapdl.parres('parm.PARM') """ - if not fname: - fname = self.jobname - - fname = self._get_file_name( - fname=fname, ext=ext, default_extension="parm" - ) # Although documentation says `PARM` - - if self._mode == "grpc": # grpc mode - if self.is_local: - # It must be a file! - if os.path.isfile(fname): - # And it exist! - filename = os.path.join(os.getcwd(), fname) - elif fname in self.list_files(): # - # It exists in the Mapdl working directory - filename = os.path.join(self.directory, fname) - elif os.path.dirname(fname): - raise ValueError( - f"'{fname}' appears to be an incomplete directory path rather than a filename." - ) - else: - # Finally - raise FileNotFoundError(f"Unable to locate filename '{fname}'") - - else: - if not os.path.dirname(fname): - # might be trying to run a local file. Check if the - # file exists remotely. - if fname not in self.list_files(): - self.upload(fname, progress_bar=False) - else: - self.upload(fname, progress_bar=False) - filename = os.path.basename(fname) - else: - filename = fname - - return self.input(filename) + return self.run(f"PARRES, {lab}, {fname}, {ext}") def parsav(self, lab="", fname="", ext="", **kwargs): """Writes parameters to a file. diff --git a/src/ansys/mapdl/core/_commands/session/files.py b/src/ansys/mapdl/core/_commands/session/files.py index bb0c323f63..2fef06c84b 100644 --- a/src/ansys/mapdl/core/_commands/session/files.py +++ b/src/ansys/mapdl/core/_commands/session/files.py @@ -1,7 +1,5 @@ """These SESSION commands are for file operations, such as deleting, copying, and listing.""" -import os - class Files: def anstoasas(self, fname="", key="", **kwargs): @@ -505,34 +503,7 @@ def lgwrite(self, fname="", ext="", kedit="", remove_grpc_extra=True, **kwargs): K,2,2,0,0 """ - # always add extension to fname - if ext: - fname = fname + f".{ext}" - - # seamlessly deal with remote instances in gRPC mode - target_dir = None - is_grpc = "Grpc" in type(self).__name__ - if is_grpc and fname: - if not self._local and os.path.basename(fname) != fname: - target_dir, fname = os.path.dirname(fname), os.path.basename(fname) - - # generate the log and download if necessary - output = self.run(f"LGWRITE,{fname},,,{kedit}", **kwargs) - if not fname: - # defaults to .lgw - fname = self.jobname + ".lgw" - if target_dir is not None: - self.download(fname, target_dir=target_dir) - - # remove extra grpc /OUT commands - if remove_grpc_extra and is_grpc and target_dir: - filename = os.path.join(target_dir, fname) - with open(filename, "r") as fid: - lines = [line for line in fid if not line.startswith("/OUT")] - with open(filename, "w") as fid: - fid.writelines(lines) - - return output + return self.run(f"LGWRITE,{fname},{ext},,{kedit}") def starlist(self, fname="", ext="", **kwargs): """Displays the contents of an external, coded file. diff --git a/src/ansys/mapdl/core/_commands/session/list_controls.py b/src/ansys/mapdl/core/_commands/session/list_controls.py index 86c300b479..45c4cb455b 100644 --- a/src/ansys/mapdl/core/_commands/session/list_controls.py +++ b/src/ansys/mapdl/core/_commands/session/list_controls.py @@ -26,9 +26,7 @@ def com(self, comment="", **kwargs): This command is valid anywhere. """ - command = "/COM,%s" % (str(comment)) - if self.print_com and not self.mute and not kwargs.get("mute", False): - print(command) + command = f"/COM, {comment}" return self.run(command, **kwargs) def golist(self, **kwargs): diff --git a/src/ansys/mapdl/core/_commands/solution/load_step_operations.py b/src/ansys/mapdl/core/_commands/solution/load_step_operations.py index 988ea3ba05..30d2561bdf 100644 --- a/src/ansys/mapdl/core/_commands/solution/load_step_operations.py +++ b/src/ansys/mapdl/core/_commands/solution/load_step_operations.py @@ -188,9 +188,7 @@ def lssolve(self, lsmin="", lsmax="", lsinc="", **kwargs): >>> mapdl.lssolve(1, 2) """ - with self.non_interactive: - self.run(f"LSSOLVE,{lsmin},{lsmax},{lsinc}", **kwargs) - return self.last_response + return self.run(f"LSSOLVE,{lsmin},{lsmax},{lsinc}", **kwargs) def lswrite(self, lsnum="", **kwargs): """Writes load and load step option data to a file. diff --git a/src/ansys/mapdl/core/mapdl.py b/src/ansys/mapdl/core/mapdl.py index c64ca5b3b6..cf06cd6d7d 100644 --- a/src/ansys/mapdl/core/mapdl.py +++ b/src/ansys/mapdl/core/mapdl.py @@ -4768,7 +4768,11 @@ def use(self, *args, **kwargs): # Update arg because the path is no longer needed args = (base_name, *args[1:]) - return super().use(*args, **kwargs) + + with self.non_interactive: + super().use(*args, **kwargs) + + return self._response # returning last response @wraps(Commands.set) def set( @@ -5066,3 +5070,185 @@ def cmplot(self, label: str = "", entity: str = "", keyword: str = "", **kwargs) self.cmsel("s", "__tmp_cm__", entity=entity) self.components.select(cmps_names) return output + + @wraps(Commands.inquire) + def inquire(self, strarray="", func="", arg1="", arg2=""): + """Wraps original INQUIRE function""" + func_options = [ + "LOGIN", + "DOCU", + "APDL", + "PROG", + "AUTH", + "USER", + "DIRECTORY", + "JOBNAME", + "RSTDIR", + "RSTFILE", + "RSTEXT", + "OUTPUT", + "ENVNAME", + "TITLE", + "EXIST", + "DATE", + "SIZE", + "WRITE", + "READ", + "EXEC", + "LINES", + ] + + if strarray.upper() in func_options and func.upper() not in func_options: + # Likely you are using the old ``_Mapdl.inquire`` implementation. + raise ValueError( + "Arguments of this method have changed. `Mapdl.inquire` now includes the optional `strarray` parameter " + f"as the first argument. Either use `inquire(func={strarray})`, or `inquire(" + ", {strarray})`" + ) + + if func == "": + func = "DIRECTORY" + + if strarray.upper() not in func_options and func.upper() not in func_options: + raise ValueError( + f"The arguments (strarray='{strarray}', func='{func}') are not valid." + ) + + response = self.run(f"/INQUIRE,{strarray},{func},{arg1},{arg2}", mute=False) + if func.upper() in [ + "ENV", + "TITLE", + ]: # the output is multiline, we just need the last line. + response = response.splitlines()[-1] + + return response.split("=")[1].strip() + + @wraps(Commands.parres) + def parres(self, lab="", fname="", ext="", **kwargs): + """Wraps the original /PARRES function""" + if not fname: + fname = self.jobname + + fname = self._get_file_name( + fname=fname, ext=ext, default_extension="parm" + ) # Although documentation says `PARM` + + # Getting the path for local/remote + filename = self._get_file_path(fname, progress_bar=False) + + return self.input(filename) + + @wraps(Commands.lgwrite) + def lgwrite(self, fname="", ext="", kedit="", remove_grpc_extra=True, **kwargs): + """Wraps original /LGWRITE""" + + # always add extension to fname + if ext: + fname = fname + f".{ext}" + + # seamlessly deal with remote instances in gRPC mode + target_dir = None + is_grpc = "Grpc" in type(self).__name__ + if is_grpc and fname: + if not self._local and os.path.basename(fname) != fname: + target_dir, fname = os.path.dirname(fname), os.path.basename(fname) + + # generate the log and download if necessary + output = super().lgwrite(fname=fname, kedit=kedit, **kwargs) + + if not fname: + # defaults to .lgw + fname = self.jobname + ".lgw" + if target_dir is not None: + self.download(fname, target_dir=target_dir) + + # remove extra grpc /OUT commands + if remove_grpc_extra and is_grpc and target_dir: + filename = os.path.join(target_dir, fname) + with open(filename, "r") as fid: + lines = [line for line in fid if not line.startswith("/OUT")] + with open(filename, "w") as fid: + fid.writelines(lines) + + return output + + @wraps(Commands.vwrite) + def vwrite( + self, + par1="", + par2="", + par3="", + par4="", + par5="", + par6="", + par7="", + par8="", + par9="", + par10="", + par11="", + par12="", + par13="", + par14="", + par15="", + par16="", + par17="", + par18="", + par19="", + **kwargs, + ): + """Wrapping *VWRITE""" + + # cannot be run in interactive mode + if not self._store_commands: + raise MapdlRuntimeError( + "VWRTIE cannot run interactively. \n\nPlease use " + "``with mapdl.non_interactive:``" + ) + + return super().vwrite( + par1=par1, + par2=par2, + par3=par3, + par4=par4, + par5=par5, + par6=par6, + par7=par7, + par8=par8, + par9=par9, + par10=par10, + par11=par11, + par12=par12, + par13=par13, + par14=par14, + par15=par15, + par16=par16, + par17=par17, + par18=par18, + par19=par19, + **kwargs, + ) + + @wraps(Commands.nrm) + def nrm(self, name="", normtype="", parr="", normalize="", **kwargs): + """Wraps *NRM""" + if not parr: + parr = "__temp_par__" + super().nrm( + name=name, normtype=normtype, parr=parr, normalize=normalize, **kwargs + ) + return self.parameters[parr] + + @wraps(Commands.com) + def com(self, comment="", **kwargs): + """Wraps /COM""" + if self.print_com and not self.mute and not kwargs.get("mute", False): + print("/COM,%s" % (str(comment))) + + return super().com(comment=comment, **kwargs) + + @wraps(Commands.lssolve) + def lssolve(self, lsmin="", lsmax="", lsinc="", **kwargs): + """Wraps LSSOLVE""" + with self.non_interactive: + super().lssolve(lsmin=lsmin, lsmax=lsmax, lsinc=lsinc, **kwargs) + return self.last_response diff --git a/src/ansys/mapdl/core/misc.py b/src/ansys/mapdl/core/misc.py index 94268eca81..e30b3ddaa8 100644 --- a/src/ansys/mapdl/core/misc.py +++ b/src/ansys/mapdl/core/misc.py @@ -844,7 +844,7 @@ def title(self): @title.setter def title(self, title): - return self._mapdl.title(title) + return self._mapdl.run(f"/TITLE, {title}") @property @update_information_first(True) diff --git a/tests/test_mapdl.py b/tests/test_mapdl.py index e46df07a95..e7b311b3a3 100644 --- a/tests/test_mapdl.py +++ b/tests/test_mapdl.py @@ -212,12 +212,45 @@ def test_global_mute(mapdl): def test_parsav_parres(mapdl, cleared, tmpdir): arr = np.random.random((10, 3)) + mapdl.parameters["MYARR"] = arr - mapdl.parsav("ALL", "tmp.txt") + mapdl.parsav("ALL", "db.txt") + mapdl.download("db.txt") + + # Restoring mapdl.clear() - mapdl.parres("ALL", "tmp.txt") + mapdl.parres("ALL", "db.txt") assert np.allclose(mapdl.parameters["MYARR"], arr) + # test no filename + mapdl.clear() + mapdl.parameters["MYARR"] = arr + mapdl.parsav("ALL") + + mapdl.clear() + mapdl.parres("ALL") + assert np.allclose(mapdl.parameters["MYARR"], arr) + + # Test upload local + mapdl.clear() + if "db.txt" in mapdl.list_files(): + mapdl.slashdelete("db.txt") + + mapdl.parres("NEW", "db", "txt") + assert np.allclose(mapdl.parameters["MYARR"], arr) + + # Test directory error + mapdl.clear() + with pytest.raises(FileNotFoundError): + mapdl.parres("NEW", os.getcwd()) + + # Test non-existing file + mapdl.clear() + with pytest.raises(FileNotFoundError): + mapdl.parres("change", "mydummy", "file") + + os.remove("db.txt") + @requires("grpc") def test_no_results(mapdl, cleared, tmpdir): @@ -2119,6 +2152,40 @@ def test_saving_selection_context(mapdl, cube_solve): assert "nod_selection_4" not in mapdl.components +def test_inquire_invalid(mapdl): + with pytest.raises(ValueError, match="Arguments of this method have changed"): + mapdl.inquire("directory") + + with pytest.raises(ValueError, match="The arguments "): + mapdl.inquire("dummy", "hi") + + +def test_inquire_default(mapdl): + mapdl.title = "heeeelloo" + assert mapdl.directory == mapdl.inquire() + + +def test_vwrite_error(mapdl): + with pytest.raises(MapdlRuntimeError): + mapdl.vwrite("adf") + + +def test_vwrite(mapdl): + with mapdl.non_interactive: + mapdl.run("/out,test_vwrite.txt") + mapdl.vwrite("'hello'") + mapdl.run("(1X, A8)") + mapdl.run("/out") + + mapdl.download("test_vwrite.txt") + + with open("test_vwrite.txt", "r") as fid: + content = fid.read() + + assert "hello" == content.strip() + os.remove("test_vwrite.txt") + + def test_get_array_non_interactive(mapdl, solved_box): mapdl.allsel() with pytest.raises(MapdlRuntimeError): From 67f9cb07b9fd6a6429f0d731a7c4845bbaf119f7 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Tue, 21 Nov 2023 12:04:30 +0100 Subject: [PATCH 24/30] Adding missing envvar for connection commands in CICD (#2380) * Adding env var to container launcher. Activating tests * Adding env var to local Activating catia test * activating all tests so I can revaluate * activating all tests so I can revaluate * reverting to main --- .ci/start_mapdl.sh | 1 + .ci/start_mapdl_ubuntu.sh | 1 + .github/workflows/ci.yml | 1 + 3 files changed, 3 insertions(+) diff --git a/.ci/start_mapdl.sh b/.ci/start_mapdl.sh index 170f7c0284..3ce2377674 100755 --- a/.ci/start_mapdl.sh +++ b/.ci/start_mapdl.sh @@ -14,6 +14,7 @@ docker run \ -p $PYMAPDL_DB_PORT:50055 \ --shm-size=1gb \ -e I_MPI_SHM_LMT=shm \ + -e P_SCHEMA=/ansys_inc/ansys/ac4/schema \ --oom-kill-disable \ --memory=6656MB \ --memory-swap=16896MB \ diff --git a/.ci/start_mapdl_ubuntu.sh b/.ci/start_mapdl_ubuntu.sh index 2e3f511dae..08dfd9b4ca 100755 --- a/.ci/start_mapdl_ubuntu.sh +++ b/.ci/start_mapdl_ubuntu.sh @@ -15,6 +15,7 @@ docker run \ -p $PYMAPDL_DB_PORT:50055 \ --shm-size=1gb \ -e I_MPI_SHM_LMT=shm \ + -e P_SCHEMA=/ansys_inc/v222/ansys/ac4/schema \ -w /jobs \ -u=0:0 \ --oom-kill-disable \ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3f7c465643..86504f3c1d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -477,6 +477,7 @@ jobs: env: ON_LOCAL: true ON_UBUNTU: true + P_SCHEMA: "/ansys_inc/v222/ansys/ac4/schema" PYTEST_TIMEOUT: 120 # seconds. Limit the duration for each unit test steps: From e1034f32584eaed2c9059584be9aa71704f5206d Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Tue, 21 Nov 2023 12:22:11 +0100 Subject: [PATCH 25/30] API and contribution sections small reorganization (#2491) * API reog. Extended documentation about writing example and developing PyMAPDL. * Apply suggestions from code review Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> Co-authored-by: Maxime Rey <87315832+MaxJPRey@users.noreply.github.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update doc/source/getting_started/develop_pymapdl.rst * Update doc/source/links.rst * Simplifying accept file * fixing title --------- Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> Co-authored-by: Maxime Rey <87315832+MaxJPRey@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- doc/source/api/building_example.rst | 92 ----- doc/source/api/index.rst | 2 - doc/source/api/unit_testing.rst | 174 --------- doc/source/getting_started/contribution.rst | 142 +++----- .../getting_started/develop_pymapdl.rst | 335 ++++++++++++++++++ .../getting_started/write_documentation.rst | 232 ++++++++++++ doc/source/links.rst | 10 + doc/source/user_guide/troubleshoot.rst | 3 +- doc/styles/Vocab/ANSYS/accept.txt | 13 +- 9 files changed, 637 insertions(+), 366 deletions(-) delete mode 100644 doc/source/api/building_example.rst delete mode 100644 doc/source/api/unit_testing.rst create mode 100644 doc/source/getting_started/develop_pymapdl.rst create mode 100644 doc/source/getting_started/write_documentation.rst diff --git a/doc/source/api/building_example.rst b/doc/source/api/building_example.rst deleted file mode 100644 index ee5d1f9a04..0000000000 --- a/doc/source/api/building_example.rst +++ /dev/null @@ -1,92 +0,0 @@ -.. _ref_building_example: - - -=================== -Building an example -=================== - -.. currentmodule:: ansys.mapdl.core.building_example - -To run the documentation, you need to have the correct versions of each tool. To do so, execute the -following instruction. - -.. code:: console - - pip install -r requirements/requirements_docs.txt - - -The Sphinx configuration is in the file -`conf.py `_ in :file:`doc/source`. - - -To run the sphinx tool: - -.. code:: pwsh-session - - doc\make.bat html - - -There are three types of examples: dynamic, static, and semi-static. - -* `Dynamic examples`_ -* `Static examples`_ -* `Semi-dynamic examples`_ - - -Dynamic examples ----------------- - -The dynamic examples are based on Python files and must be able to run in under three minutes. - -They are in the `examples `_ directory in this repository. - -.. vale off - -Example: `2d_plate_with_a_hole.py `_ -.. vale on - -Here is a link to this dynamic example: -`MAPDL 2D Plane Stress Concentration Analysis `_ - -When an example is executed, **Total running time of the script** appears at the end of -the document. - - -Static examples ---------------- - -Static examples are based on RST files and are not executed. - -They are in the `doc\source `_ directory. -.. vale off - -Example: `krylov_example.rst `_ -.. vale on - -Here is a link to this static example: `Harmonic analysis using the frequency-sweep Krylov method `_ - - -Semi-dynamic examples ---------------------- - -Semi-dynamic examples are RST files that execute Python code using this RST directive: - -.. code:: rst - - .. jupyter-execute:: - :hide-code: - - -.. vale off - -Example: `tecfricstir.rst `_ -.. vale on - -Here is a link to this semi-dynamic example: `Friction Stir Welding (FSW) Simulation `_ - - -Recommendations ---------------- - -As dynamic examples must run each time documentation is built, make sure that they are very short. -To get around the problem of execution time, feel free to use static or semi-static examples. diff --git a/doc/source/api/index.rst b/doc/source/api/index.rst index e452fe45ff..459792ce43 100644 --- a/doc/source/api/index.rst +++ b/doc/source/api/index.rst @@ -36,5 +36,3 @@ PyMAPDL, see :ref:`ref_mapdl_commands`. Pyansys Math solution xpl - building_example - unit_testing diff --git a/doc/source/api/unit_testing.rst b/doc/source/api/unit_testing.rst deleted file mode 100644 index 74ac56865b..0000000000 --- a/doc/source/api/unit_testing.rst +++ /dev/null @@ -1,174 +0,0 @@ -.. _ref_unit_testing_contributing: - -Unit testing -============ - -Unit tests validate the software by testing that the logic -implemented inside a certain method, class, or module is -working as expected. They should be as atomic and -independent as possible. - -Unit testing is highly important. The tests verify that code -changes are consistent with other parts of the code -and verify that these changes are implemented properly. - -Unit tests are in the `tests `_ directory in this repository, -along with integration tests. The difference between -a unit test and an integration test is that the latter -tests several units of the code to ensure that they all work together. - -To verify that all code is properly tested, you must ensure that every piece -of code is used (covered) in at least one unit test. In this repository, the -`Codecov `_ tool generates a coverage report of the -committed code. It details how merging a pull request would impact coverage. It -is one of the checks that must run successfully to merge code changes. - - -.. figure:: ../images/codecov_increase.png - :width: 400pt - - -Coverage example ----------------- - -To show how the coverage works, assume that you have -this library: - -**Awesome library** - - -.. code:: python - - def get_report_colors(theme): - if theme == "weather": - colors = ["blue", "lightblue", "grey"] - elif theme == "traffic": - colors = ["red", "orange", "yellow"] - else: - colors = ["red", "blue", "green"] - - return colors - - -**Tests** - -You can opt to run the tests with this configuration: - -.. code:: python - - def test_get_report_colors(): - assert get_report_colors("weather") == ["blue", "lightblue", "grey"] - assert get_report_colors("traffic") == ["red", "orange", "yellow"] - assert get_report_colors("other") == ["red", "blue", "green"] - - -Or, if a method is a bit more complex, you can split the case in different tests: - -.. code:: python - - def test_get_report_colors_weather(): - assert get_report_colors("weather") == ["blue", "lightblue", "grey"] - - - def test_get_report_colors_traffic(): - assert get_report_colors("traffic") == ["red", "orange", "yellow"] - - - def test_get_report_colors_other(): - assert get_report_colors("other") == ["red", "blue", "green"] - - -While the code coverage in either case is 100% for the function, the second case is -more useful for debugging the function. - - -Continuous Integration and Continuous Deployment (CI/CD) approach ------------------------------------------------------------------ - -Unit tests and integration tests are part of Continuous Integration (CI). -The automation of testing, monitoring, and deployment of newly added -code allows Continuous Deployment (CD) throughout the app lifecycle, -providing a comprehensive CI/CD approach. - -.. figure:: ../images/cicd.jpg - :width: 300pt - -Creation of a unit test ------------------------ - -In the PyMAPDL repository, `pytest `_ is used to run tests. - -The name of a ``pytest`` file must be in the form ``test_XXX.py``, where ``XXX`` -is either the function, method, or class that you are testing or some other explicative -name. In the command line, the ``-k`` argument can be used to filter the tests to run. -For more information, see `pytest usage `_. - -Here are some guidelines for creating good unit tests: - -- Assign long and descriptive names to tests. -- Use the `Codecov `_ tool to ensure all implemented code is tested. -- Check that tests return the same results each time. -- Verify that tests are independent. -- Write tests that verify only one part of the code at a time. -- Make tests as short and fast as possible. - -`What makes a good unit test `_ -is an exhaustive list of tips for creating good unit tests. - -Most PyMAPDL tests require a connection to a running instance of -MAPDL, which makes them integration tests. If your test -requires a running MAPDL instance, you can use the PyMAPDL -`mapdl `_ method in your function signature. -It is executed upstream of each test and not within all tests. - -.. code:: python - - def test_my_new_feature(mapdl): # pass the 'mapdl' fixture as an argument. - mapdl.prep7() - # .... more code - - return True # if everything goes ok until here - - -Example --------- - -.. TO BE MODIFIED - -The `test_component.py `_ file contains -the unit tests and integration tests of the -:class:`ComponentManager `. -These are just some of the many tests that you can find in the -`test directory `_. - -Here are some examples of how you use ``pytest``: - -.. code:: python - - import pytest - - - # 'cube_geom_and_mesh' is another fixture defined in 'conftest.py' - @pytest.fixture(scope="function") - def basic_components(mapdl, cube_geom_and_mesh): - """Given a model in 'cube_geom_and_mesh', let's define some components to work with later.""" - mapdl.components["mycomp1"] = "NODE", [1, 2, 3] - mapdl.components["mycomp2"] = "KP", [1, 3] - - mapdl.cmsel("s", "mycomp1") - mapdl.cmsel("a", "mycomp2") - - - def test_dunder_methods_keys(mapdl, basic_components): - assert ["MYCOMP1", "MYCOMP2"] == list(mapdl.components.names()) - - - def test_dunder_methods_types(mapdl, basic_components): - assert ["NODE", "KP"] == list(mapdl.components.types()) - - - def test_dunder_methods_items(mapdl, basic_components): - assert [("MYCOMP1", "NODE"), ("MYCOMP2", "KP")] == list(mapdl.components.items()) - - -For further explanations, see the `pytest documentation `_. \ No newline at end of file diff --git a/doc/source/getting_started/contribution.rst b/doc/source/getting_started/contribution.rst index 8c2662d325..4ed5b5b194 100644 --- a/doc/source/getting_started/contribution.rst +++ b/doc/source/getting_started/contribution.rst @@ -4,106 +4,70 @@ Contributing ============ -Overall guidance on contributing to a PyAnsys library appears in the -`Contributing `_ topic -in the *PyAnsys Developer's Guide*. Ensure that you are thoroughly familiar -with it and all `Coding style `_ before attempting to -contribute to PyMAPDL. - -The following contribution information is specific to PyMAPDL. +.. toctree:: + :hidden: + :maxdepth: 3 -Cloning the PyMAPDL repository -============================== + write_documentation + develop_pymapdl -Run this code to clone and install the latest version of PyMAPDL in development mode: -.. code:: console +There are several ways to contribute to PyMAPDL. - git clone https://github.com/ansys/pymapdl - cd pymapdl - pip install pip -U - pip install -e . +* `Answer discussions`_ +* `Post issues`_ +* :ref:`write_documentation` +* :ref:`developing_pymapdl` +Overall guidance on contributing to a PyAnsys library appears in the +`Contributing `_ topic +in the *PyAnsys Developer's Guide*. Ensure that you are thoroughly familiar +with it and the `Coding style `_ before attempting to +contribute to PyMAPDL. + -Posting issues -============== - -Use the `PyMAPDL Issues `_ -page to submit questions, report bugs, and request new features. When possible, -use these issue templates: +Answer discussions +================== + +Answering discussions is an excellent way to contribute to PyMAPDL, and +it does not require any setup, just a GitHub account. +It is probably the first step towards becoming a full PyMAPDL developer, since it +helps you deepen your understanding of the project. Engaging in +discussions often requires a thorough grasp of the project's goals and +challenges. +Your contributions can help other users or contributors who +may be facing similar issues, making the repository more welcoming and +inclusive. By providing answers or solutions, you can directly contribute to the project's +success, maintain its health, and encourage a positive, open source ecosystem. + +To discover how you can help, see the `PyMAPDL Discussions `_ page. + + +Post issues +=========== + +Posting issues in a repository is a valuable contribution that benefits you, the +repository, and PyMAPDL as a whole. It allows you to voice concerns, suggest +improvements, or report bugs, which can lead to a more robust and user-friendly +project. It also offers an opportunity for you to engage with the project's +community, learn from others, and gain experience in issue tracking and +collaboration. +For the repository, issues serve as a structured way to track and +prioritize work, helping maintainers understand the needs of users and guide the +project's development. It's an excellent way to contribute because it enhances +the project's quality, fosters transparency, and encourages the collective +effort of the community to continuously improve and innovate. + +Use the `PyMAPDL Issues `_ page to submit questions, report bugs, +and request new features. +When possible, use these issue templates: * **🐞 Bug, problem, or error**: Fill a bug report here * **📖 Documentation issue**: Modifications to the documentation only * **🎓 Adding an example**: Proposing a new example for the library * **💡 New feature**: Enhancements to the code -If your issue does not fit into one of these categories, click in `Open a blank issue `_. - - -Viewing PyMAPDL documentation -============================= - -Documentation for the latest stable release of PyMAPDL is hosted at -`PyMAPDL Documentation `_. - -In the upper right corner of the documentation's title bar, there is an option -for switching from viewing the documentation for the latest stable release -to viewing the documentation for the development version or previously -released versions. - -Testing MAPDL -============= - -If you do not have MAPDL installed locally but still want to run the -unit testing, you must set up the following environment variables. - -**On Windows** - -.. code:: pwsh-session - - SET PYMAPDL_START_INSTANCE=False - SET PYMAPDL_PORT= (default 50052) - SET PYMAPDL_IP= (default 127.0.0.1) - -**On Linux** - -.. code:: console - - export PYMAPDL_START_INSTANCE=False - export PYMAPDL_PORT= (default 50052) - export PYMAPDL_IP= (default 127.0.0.1) - -This tells ``ansys.mapdl.core`` to attempt to connect to the existing -MAPDL service by default when the ``launch_mapdl`` function is used. - -Additionally you can use the environment variables ``PYMAPDL_MAPDL_EXEC`` -and ``PYMAPDL_MAPDL_VERSION`` to specify MAPDL executable path and the -version to launch (if multiple versions of MAPDL are installed). - - -Code style -========== - -PyMAPDL follows PEP8 standard as outlined in the `PyAnsys Development Guide -`_ and implements style checking using -`pre-commit `_. - -To ensure your code meets minimum code styling standards, run:: - - pip install pre-commit - pre-commit run --all-files - -You can also install this as a pre-commit hook by running:: - - pre-commit install - -This way, it's not possible for you to push code that fails the style checks. For example:: - - $ pre-commit install - $ git commit -am "added my cool feature" - black....................................................................Passed - isort....................................................................Passed - flake8...................................................................Passed - codespell................................................................Passed +If your issue does not fit into one of these categories, click +`Open a blank issue `_. \ No newline at end of file diff --git a/doc/source/getting_started/develop_pymapdl.rst b/doc/source/getting_started/develop_pymapdl.rst new file mode 100644 index 0000000000..0d4c19c507 --- /dev/null +++ b/doc/source/getting_started/develop_pymapdl.rst @@ -0,0 +1,335 @@ + +.. _developing_pymapdl: + +============ +Develop code +============ + +You can help improve PyMAPDL by fixing a bug or developing a new feature. +To do either, you must set up the repository on your local machine as per the +explanations in the following sections. + + +Clone the PyMAPDL repository +============================ + +Before cloning the PyMAPDL repository, you must install a version control system such as Git. +You can this run this code to clone the latest development version of PyMAPDL: + +.. code:: console + + git clone https://github.com/ansys/pymapdl + cd pymapdl + + + +Create a Python virtual environment +=================================== + +To avoid dependency conflicts and more easily manage upgrades, you should install PyMAPDL in its own virtual environment. For detailed information on how to install Python and create a virtual environment, see +`Setting up your development environment `_. + +Install PyMAPDL in development mode +=================================== + +Install the latest version of PyMAPDL in development mode with these commands: + + +.. code:: console + + cd pymapdl + pip install pip -U + pip install -e . + + +If you are going to do testing, you must install the testing dependencies with this command: + + +.. code:: console + + pip install -e '.[tests]' + + +Develop PyMAPDL +=============== + +.. epigraph:: *Now it is time to develop PyMAPDL!* + +Developing code in a repository, particularly when using version control systems +like Git, involves a set of essential guidelines to ensure efficient +collaboration, code management, and tracking changes. Here are the main +guidelines for developing code in a repository: + +#. **Use branches**: Create branches for different features, bug fixes, or + experiments. This keeps changes isolated and facilitates parallel + development. + +#. **Write descriptive commit messages**: Provide clear and concise commit + messages that explain the purpose and context of the changes. Follow a + consistent style. + +#. **Commit frequently**: Make small, meaningful commits frequently. Avoid + making a large number of unrelated changes in a single commit. + +#. **Pull before you push**: Always update your local branch with the latest + changes from the remote repository before pushing your own changes to avoid + conflicts. + +#. **Use pull requests (PRs)**: Use PRs to submit your changes for review. + This allows for discussion and validation before merging into the main branch. + +#. **Write good documentation**: Maintain clear and up-to-date documentation for your + contribution or changes, including comments in code, and relevant project + documentation in rST or Markdown files. + If you implement a new feature or change the behaviour of the library in any way, + remember to mention it somewhere in the documentation (rST files in :file:`doc\source` directory) + Follow the `numpydoc `_ convention for documenting code. + +#. **Test your changes**: Thoroughly test your changes to ensure that they work + as expected. If applicable, create or update the unit tests that run on the + continuous integration/continuous deployment (CI/CD) pipelines to catch issues early + and ensure reliable deployments. For more information, see `Unit testing`_. + +#. **Respect code style and standards**: Follow code style + guidelines and adhere to coding standards specific to your language or + framework. + +#. **Collaborate and communicate**: Communicate with team members, provide + updates on your progress, and resolve any conflicts promptly. + +#. **Ask for help**: To ensure code quality, identify issues, and share knowledge, + ask PyMAPDL developers to assist you and review your code. + If you need help or guidance, mention ``@ansys/pymapdl-maintainers`` in a comment + so they they are notified. + +By following these guidelines, you can ensure smooth and organized code +development within a repository, fostering collaboration, code quality, and feature enhancement. + + +.. _ref_unit_testing_contributing: + +Unit testing +============ + +Unit tests validate the software by testing that the logic implemented inside a +certain method, class, or module is working as expected. They should be as +atomic and independent as possible. + +Unit testing is highly important. The tests verify that code changes are +consistent with other parts of the code and verify that these changes are +implemented properly. + +Unit tests are in the `tests `_ directory in this repository, +along with integration tests. The difference between a unit test and an +integration test is that the latter tests several units of the code to ensure +that they all work together. + +To verify that all code is properly tested, you must ensure that every piece of +code is used (covered) in at least one unit test. In this repository, the +`Codecov `_ tool generates a coverage report of the committed code. It +indicates how merging a pull request would impact coverage. The generation of this report is one of the +checks that must run successfully to merge code changes. + + +.. figure:: ../images/codecov_increase.png + :width: 400pt + + +Coverage example +---------------- + +To show how the coverage works, assume that you have +this library: + +**Awesome library** + + +.. code:: python + + def get_report_colors(theme): + if theme == "weather": + colors = ["blue", "lightblue", "grey"] + elif theme == "traffic": + colors = ["red", "orange", "yellow"] + else: + colors = ["red", "blue", "green"] + + return colors + + +**Tests** + +You can opt to run the tests with this configuration: + +.. code:: python + + def test_get_report_colors(): + assert get_report_colors("weather") == ["blue", "lightblue", "grey"] + assert get_report_colors("traffic") == ["red", "orange", "yellow"] + assert get_report_colors("other") == ["red", "blue", "green"] + + +Or, if a method is a bit more complex, you can split the case in different tests: + +.. code:: python + + def test_get_report_colors_weather(): + assert get_report_colors("weather") == ["blue", "lightblue", "grey"] + + + def test_get_report_colors_traffic(): + assert get_report_colors("traffic") == ["red", "orange", "yellow"] + + + def test_get_report_colors_other(): + assert get_report_colors("other") == ["red", "blue", "green"] + + +While the code coverage in either case is 100% for the function, the second case is +more useful for debugging the function. + + +Continuous integration and continuous deployment +------------------------------------------------ + +Unit tests and integration tests are part of continuous integration (CI). +The automation of testing, monitoring, and deployment of newly added +code allows continuous deployment (CD) throughout the app lifecycle, +providing a comprehensive CI/CD approach. + +.. figure:: ../images/cicd.jpg + :width: 300pt + +Creation of a unit test +----------------------- + +In the PyMAPDL repository, `pytest `_ is used to run tests. + +The name of a ``pytest`` file must be in the form ``test_XXX.py``, where ``XXX`` +is either the function, method, or class that you are testing or some other explicative +name. In the command line, you can use the ``-k`` argument to filter the tests to run. +For more information, see `pytest usage `_. + +Here are some guidelines for creating good unit tests: + +- Assign long and descriptive names to tests. +- Use the `Codecov `_ tool to ensure that all implemented code is tested. +- Check that tests return the same results each time. +- Verify that tests are independent. +- Write tests that verify only one part of the code at a time. +- Make tests as short and fast as possible. + +`What makes a good unit test? `_ +is an exhaustive list of tips for creating good unit tests. + +Most PyMAPDL tests require a connection to a running instance of +MAPDL, which makes them integration tests. If your test +requires a running MAPDL instance, you can use the PyMAPDL +`mapdl `_ method in your function signature. +It is executed upstream of each test and not within all tests. + +.. code:: python + + def test_my_new_feature(mapdl): # pass the 'mapdl' fixture as an argument. + mapdl.prep7() + # .... more code + + return True # if everything goes ok until here + + +If you do not have MAPDL installed locally but still want to run the +unit testing, you must set up the following environment variables. + +In Windows, use this code: + +.. code:: pwsh-session + + SET PYMAPDL_START_INSTANCE=False + SET PYMAPDL_PORT= (default 50052) + SET PYMAPDL_IP= (default 127.0.0.1) + +In Linux, use this code: + +.. code:: console + + export PYMAPDL_START_INSTANCE=False + export PYMAPDL_PORT= (default 50052) + export PYMAPDL_IP= (default 127.0.0.1) + +These environment variables tell PyMAPDL to attempt to connect to the existing +MAPDL service by default when the ``launch_mapdl`` function is used. + +Additionally, you can use the :envvar:`PYMAPDL_MAPDL_EXEC` and :envvar:`PYMAPDL_MAPDL_VERSION` +environment variables to specify the MAPDL executable path and the version to launch (if +multiple versions of MAPDL are installed). + + +Example +-------- + +.. TO BE MODIFIED + +The `test_component.py `_ file contains +the unit tests and integration tests for the +:class:`ComponentManager ` class. +These tests are just some of the many in the `test directory `_. + +Here are some examples of how you use ``pytest``: + +.. code:: python + + import pytest + + + # 'cube_geom_and_mesh' is another fixture defined in 'conftest.py' + @pytest.fixture(scope="function") + def basic_components(mapdl, cube_geom_and_mesh): + """Given a model in 'cube_geom_and_mesh', define some components to work with later.""" + mapdl.components["mycomp1"] = "NODE", [1, 2, 3] + mapdl.components["mycomp2"] = "KP", [1, 3] + + mapdl.cmsel("s", "mycomp1") + mapdl.cmsel("a", "mycomp2") + + + def test_dunder_methods_keys(mapdl, basic_components): + assert ["MYCOMP1", "MYCOMP2"] == list(mapdl.components.names()) + + + def test_dunder_methods_types(mapdl, basic_components): + assert ["NODE", "KP"] == list(mapdl.components.types()) + + + def test_dunder_methods_items(mapdl, basic_components): + assert [("MYCOMP1", "NODE"), ("MYCOMP2", "KP")] == list(mapdl.components.items()) + + +For further explanations, see the `pytest documentation `_. + + + +Code style +========== + +PyMAPDL follows the PEP8 standard as outlined in the `PyAnsys Development Guide +`_ and implements style checking using +`pre-commit `_. + +To ensure your code meets minimum code styling standards, run these commands:: + + pip install pre-commit + pre-commit run --all-files + +You can also install this as a pre-commit hook by running this command:: + + pre-commit install + +This way, it's not possible for you to push code that fails the style checks. For example:: + + $ pre-commit install + $ git commit -am "added my cool feature" + black....................................................................Passed + isort....................................................................Passed + flake8...................................................................Passed + codespell................................................................Passed + diff --git a/doc/source/getting_started/write_documentation.rst b/doc/source/getting_started/write_documentation.rst new file mode 100644 index 0000000000..7b03e0e9c4 --- /dev/null +++ b/doc/source/getting_started/write_documentation.rst @@ -0,0 +1,232 @@ +.. _write_documentation: + +=================== +Write documentation +=================== + +Writing documentation is an excellent way to contribute to a project because it +plays a pivotal role in making the project more accessible and usable. Clear and +comprehensive documentation empowers users and developers to understand, +implement, and troubleshoot the project effectively. It minimizes barriers to +entry, making it easier for newcomers to get involved and for existing +contributors to be more productive. + +Good documentation also reduces the burden on maintainers, +as it can answer common questions and help prevent issues. By +creating or improving documentation, you not only enhance the project's quality +but also facilitate knowledge sharing and community growth, making your +contribution invaluable for the project's long-term success. + +Set up your environment +======================= + +To be able to write and build the documentation, you must follow the same +steps described in :ref:`developing_pymapdl`, but in this case, you must install +documentation dependencies with this command: + +.. code:: console + + pip install -e '.[doc]' + + +Build the documentation +======================= + +PyMAPDL documentation is mainly written in reStructuredText +format, saved as ``.rst`` files in the ``doc/source`` directory. +The tool used to build the documentation from these reStructuredText files +is `Sphinx `_. + +Sphinx also build API documentation from source code as well as manages the +cross-referencing between different files, classes, methods, and more. +Additionally, it builds an `examples gallery `_, +where the capabilities of PyMAPDL can be showcased. + +The documentation can be built as HTML files or a single PDF file. + +To build the documentation as HTML files, you only need to run a single command. + +On Linux: + + +.. code:: console + + make -C doc html + +On Windows: + +.. code:: pwsh-session + + doc\make.bat html + +The HTML files for the documentation are written to the ``doc/_build/html`` directory. + +If you want to build the PDF documentation, you must first install +a LaTeX distribution like `MikTeX `_. You can then run this command: + +.. code:: console + + make -C doc pdf + +Running the command to build either HTML files or a PDF file runs the Python files in ``./examples`` in the repository root directory to generate the `examples gallery `_. +The result of running these examples is cached so that the only the changed files +are re-run the next time. + +The Sphinx configuration is in the file +`conf.py `_ in :file:`doc/source`. + + +Write documentation +=================== + +Writing good documentation for a GitHub repository is crucial to ensure that +users and contributors can understand, use, and contribute to PyMAPDL +effectively. + +Here's a short summary of how to write good documentation: + +#. **Use a consistent structure**: Organize your documentation with a clear and + consistent structure. Use headings, subheadings, and a table of contents if + necessary to help users navigate your documentation easily. + +#. **Explain configuration changes**: If you require configuration changes, provide + clear instructions on how to use this new configuration, along with examples and explanations + of why they are needed. + +#. **Usage Examples**: Include real-world usage examples, code snippets, and + explanations to demonstrate how users can make the most of PyMAPDL. + +#. **Document the API and code**: Thoroughly document each function, class, and method. Include + parameter descriptions, return values, and usage examples. Follow the + `numpydoc `_ convention for documenting code. + +#. **Tutorials and guides**: Create tutorials or guides to help users achieve + specific tasks or workflows with PyMAPDL. These can be especially + helpful for complex projects. + +#. **Troubleshooting and FAQs**: Anticipate common issues and provide solutions + in a troubleshooting section. Frequently asked questions (FAQs) can also be + helpful for addressing common queries. + +#. **Maintain and update**: Keep your documentation up to date as the project + evolves. New features, changes, and bug fixes should be reflected in the + documentation. + +#. **Solicit Feedback**: Invite users and contributors to provide feedback on + the documentation and be responsive to their suggestions and questions. + + +Vale linting tool +================= + +On the GitHub repository, the CI/CD runs `Vale `_, a powerful and extensible linting tool for +checking the writing of each pull request. +If you want to verify locally as well, you must install Vale locally: + +Installation +------------ + +#. **Install Vale**: Follow the instructions in `Installation `_ +#. **Verify installation**: To confirm that Vale is installed correctly, run this command: + + .. code:: console + + vale --version + + You should see the installed Vale version displayed in the terminal. + +Usage +----- + +Vale is a versatile tool for linting and style checking your documents, +supporting various file formats and providing a wide range of style guides. +Here's a basic example of how to use Vale in PyMAPDL: + +#. **Sync styles**: The first time you run Vale in a repository, you must + sync the styles specified in the :file:`.vale.ini` file by running this command: + + .. code:: console + + vale sync + + +#. **Lint Your Document**: To verify a document, run Vale from the command line, + specifying the file or directory you want to lint. For example: + + .. code:: console + + vale --config="./doc/.vale.ini" path/to/your_document.rst + + Vale analyzes your document, and if there are any style guide violations + or linting issues, it provides feedback in the terminal. + +Make sure you have no errors or warnings before opening your pull request. + + +.. _ref_building_example: + +Create an example +================= +There are three types of examples: dynamic, static, and semi-static. + +* `Dynamic examples`_ +* `Static examples`_ +* `Semi-dynamic examples`_ + + +Dynamic examples +---------------- + +Dynamic examples are based on Python files and must be able to run in under three minutes. + +In the PyMAPD repository, they are in the `examples `_ directory. + +.. vale off + +Example: `2d_plate_with_a_hole.py `_ +.. vale on + +Here is a link to this dynamic example: +`MAPDL 2D Plane Stress Concentration Analysis `_ + +When an example is executed, **Total running time of the script** appears at the end of +the document. + +Because dynamic examples must run each time the documentation is built, make sure that they are +very short. To get around the problem of execution time, feel free to use static or semi-static +examples. + + +Static examples +--------------- + +Static examples are based on RST files and are not executed. + +In the PyMAPDL repository, they are in the `doc\source `_ directory. +.. vale off + +Example: `krylov_example.rst `_ +.. vale on + +Here is a link to this static example: `Harmonic analysis using the frequency-sweep Krylov method `_ + + +Semi-dynamic examples +--------------------- + +Semi-dynamic examples are RST files that execute Python code using this RST directive: + +.. code:: rst + + .. jupyter-execute:: + :hide-code: + + +.. vale off + +Example: `tecfricstir.rst `_ +.. vale on + +Here is a link to this semi-dynamic example: `Friction Stir Welding (FSW) Simulation `_ + + diff --git a/doc/source/links.rst b/doc/source/links.rst index b1fb34392a..eb54e31635 100644 --- a/doc/source/links.rst +++ b/doc/source/links.rst @@ -22,6 +22,7 @@ .. _dev_guide_pyansys: https://dev.docs.pyansys.com .. _dev_guide_contributing: https://dev.docs.pyansys.com/how-to/contributing.html .. _dev_guide_coding_style: https://dev.docs.pyansys.com/coding-style/index.html +.. _dev_guide_setup_your_environment: https://dev.docs.pyansys.com/how-to/setting-up.html .. #Other libraries .. _pyvista_docs: https://docs.pyvista.org/version/stable/ @@ -108,6 +109,11 @@ .. _tds_article_web_app_1: https://towardsdatascience.com/ansys-in-a-python-web-app-part-1-post-processing-with-pydpf-44d2fbaa6135 .. _tds_article_web_app_2: https://towardsdatascience.com/ansys-in-a-python-web-app-part-2-pre-processing-solving-with-pymapdl-50428c18f8e7 .. _paraview_question_read_rst: https://discourse.paraview.org/t/reading-ansys-apdl-rst-results-in-paraview/9706 +.. _miktex: https://miktex.org +.. _numpydoc: https://numpydoc.readthedocs.io/en/latest/ +.. _sphinx: https://www.sphinx-doc.org/en/master/ +.. _vale: https://www.vale.sh +.. _vale_installation: https://vale.sh/docs/vale-cli/installation/ .. #Github links: .. _gh_creating_pat: https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token @@ -148,6 +154,10 @@ .. _pymapdl_discussion_differences_mapdl_pymapdl: https://github.com/ansys/pymapdl-reader/issues/185 .. _cartpole_example_notebook: https://cartpole.mapdl.docs.pyansys.com/ml-rl-notebook.html .. _wsl_launching_mapdl: https://github.com/ansys/pymapdl/issues/2315 +.. _pymapdl_examples_gallery: https://mapdl.docs.pyansys.com/version/stable/examples/index.html +.. _pymapdl_latest_github_release: https://github.com/ansys/pymapdl/releases/latest +.. _pymapdl_latest_pdf_doc: https://github.com/ansys/pymapdl/releases/download/v%%PYMAPDLVERSION%%.0/pymapdl-Documentation-%%PYMAPDLVERSION%%.0.pdf +.. _pymapdl_conf_file: https://github.com/ansys/pymapdl/blob/main/doc/source/conf.py .. _pymapdl_search_issues_pr: https://github.com/ansys/pymapdl/issues?q= .. _pymapdl_latest_github_release: https://github.com/ansys/pymapdl/releases/latest .. _pymapdl_latest_pdf_doc: https://github.com/ansys/pymapdl/releases/download/v%%PYMAPDLVERSION%%.0/pymapdl-Documentation-%%PYMAPDLVERSION%%.0.pdf diff --git a/doc/source/user_guide/troubleshoot.rst b/doc/source/user_guide/troubleshoot.rst index b007e0d9b0..38315fc3e9 100644 --- a/doc/source/user_guide/troubleshoot.rst +++ b/doc/source/user_guide/troubleshoot.rst @@ -34,8 +34,7 @@ script: You can attach this file to a bug report in the PyMAPDL GitHub repository for further investigation. If you are not able to identify the issue, you can open a discussion on the `PyMAPDL Discussions page `_. -If you believe you have found a bug, open an issue on the -`PyMAPDL Issues page `_. +If you believe you have found a bug, create an issue on the `PyMAPDL Issues page `_. .. _ref_launching_issue: diff --git a/doc/styles/Vocab/ANSYS/accept.txt b/doc/styles/Vocab/ANSYS/accept.txt index de0ee6a543..df7a82e475 100644 --- a/doc/styles/Vocab/ANSYS/accept.txt +++ b/doc/styles/Vocab/ANSYS/accept.txt @@ -1,10 +1,12 @@ [aA]nsys [Bb]ooleans [Cc]ommand [Pp]rompt +[Dd]ocker [Ee]igensolver [Hh]yperelasticity [Kk]eypoints [Mm]atplotlib +[Mm]ulti-[Ff]ield [Nn]umpy [Pp]ostprocess [Pp]ostprocessing @@ -14,6 +16,8 @@ [Pp]yansys [Pp]ythonic [Pp]ythonically +[Rs]ST +[Ss]ubsystem [Ss]uperelements [Vv]on Mises 2D @@ -46,8 +50,6 @@ Chao container_layout datas delet -docker -Docker dof ect eigenfrequency @@ -69,8 +71,8 @@ GPa GUI hexahedral hostname -Imagemagick -ImageMagick +HTML +Image[Mm]agick imagin importlib ist @@ -93,7 +95,6 @@ midside Mises mkdir MSc -Multi-[Ff]ield multipoint nce Newton-Raphson @@ -126,7 +127,6 @@ Radiosity Rao righ RNNN -RST singl smal sord @@ -134,7 +134,6 @@ spotweld struc subselected substep -Subsystem sur tablet thermomechanical From df48beb13d3acf02f75bf460f0a2eb67846d11c9 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Tue, 21 Nov 2023 17:34:03 +0100 Subject: [PATCH 26/30] Documenting non-interactive (#2496) * * Adding `non_interactive` section. Documenting exceptions and how to work. * Changing headers syntax. * Adding tabs apdl/python. * Avoiding retriving parameters in non_interactive * Fixing vale * Apply suggestions from code review * Apply suggestions from code review * Fixing vale * Apply suggestions from code review Co-authored-by: Camille <78221213+clatapie@users.noreply.github.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fixing vale and format issues * Apply suggestions from code review Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * Code review * Apply suggestions from code review Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> * error typo * fixing link --------- Co-authored-by: Camille <78221213+clatapie@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com> --- doc/source/links.rst | 4 + doc/source/user_guide/mapdl.rst | 455 ++++++++++++++++++++--------- src/ansys/mapdl/core/parameters.py | 13 +- tests/test_parameters.py | 12 + 4 files changed, 345 insertions(+), 139 deletions(-) diff --git a/doc/source/links.rst b/doc/source/links.rst index eb54e31635..8b4cd73b9f 100644 --- a/doc/source/links.rst +++ b/doc/source/links.rst @@ -109,12 +109,14 @@ .. _tds_article_web_app_1: https://towardsdatascience.com/ansys-in-a-python-web-app-part-1-post-processing-with-pydpf-44d2fbaa6135 .. _tds_article_web_app_2: https://towardsdatascience.com/ansys-in-a-python-web-app-part-2-pre-processing-solving-with-pymapdl-50428c18f8e7 .. _paraview_question_read_rst: https://discourse.paraview.org/t/reading-ansys-apdl-rst-results-in-paraview/9706 +.. _python_context_manager: https://docs.python.org/3/reference/datamodel.html#with-statement-context-managers .. _miktex: https://miktex.org .. _numpydoc: https://numpydoc.readthedocs.io/en/latest/ .. _sphinx: https://www.sphinx-doc.org/en/master/ .. _vale: https://www.vale.sh .. _vale_installation: https://vale.sh/docs/vale-cli/installation/ + .. #Github links: .. _gh_creating_pat: https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token .. _gh_centos_wsl_1: https://github.com/wsldl-pg/CentWSL/ @@ -161,6 +163,8 @@ .. _pymapdl_search_issues_pr: https://github.com/ansys/pymapdl/issues?q= .. _pymapdl_latest_github_release: https://github.com/ansys/pymapdl/releases/latest .. _pymapdl_latest_pdf_doc: https://github.com/ansys/pymapdl/releases/download/v%%PYMAPDLVERSION%%.0/pymapdl-Documentation-%%PYMAPDLVERSION%%.0.pdf +.. _pymapdl_discussion_speed_pymapdl_mapdl: https://github.com/ansys/pymapdl/discussions/757 + .. #Python .. _using_venv: https://docs.python.org/3/library/venv.html diff --git a/doc/source/user_guide/mapdl.rst b/doc/source/user_guide/mapdl.rst index 07e7fa7c73..67eefda1d6 100644 --- a/doc/source/user_guide/mapdl.rst +++ b/doc/source/user_guide/mapdl.rst @@ -1,18 +1,43 @@ .. _ref_mapdl_user_guide: -************************** +========================== PyMAPDL language and usage -************************** +========================== + This page gives you an overview of the PyMAPDL API for the :class:`Mapdl ` class. For more information, see :ref:`ref_mapdl_api`. Overview --------- +======== When calling MAPDL commands as functions, each command has been translated from its original MAPDL all CAPS format to a PEP8 compatible format. For example, ``ESEL`` is now the :func:`Mapdl.esel() ` method. + + +.. tab-set:: + + .. tab-item:: APDL + :sync: key1 + + .. code:: apdl + + ! Selecting elements whose centroid x coordinate + ! is between 1 and 2. + ESEL, S, CENT, X, 1, 2 + + .. tab-item:: Python + :sync: key2 + + .. code:: python + + # Selecting elements whose centroid x coordinate + # is between 1 and 2. + # returns an array of selected elements ids + mapdl.esel("S", "CENT", "X", 1, 2) + + Additionally, MAPDL commands containing a ``/`` or ``*`` have had those characters removed, unless this causes a conflict with an existing name. Most notable is @@ -23,33 +48,74 @@ method to differentiate it from ``solu``. Out of the 1500 MAPDL commands, about 15 start with ``slash (/)`` and 8 start with ``star (*)``. -MAPDL commands that normally have an empty space, such as -``ESEL,S,TYPE,,1``, should include an empty string when called by Python: -.. code:: python +.. tab-set:: - mapdl.esel("s", "type", "", 1) + .. tab-item:: APDL + :sync: key1 -Or, these commands can be called using keyword arguments: + .. code:: apdl -.. code:: python + *STATUS + /SOLU + + .. tab-item:: Python + :sync: key2 + + .. code:: python + + mapdl.startstatus() + mapdl.slashsolu() + + +MAPDL commands that can accept an empty space as argument, such as +``ESEL,S,TYPE,,1``, should include an empty string when called by Python, +or, these commands can be called using keyword arguments: + +.. tab-set:: - mapdl.esel("s", "type", vmin=1) + .. tab-item:: APDL + :sync: key1 + + .. code:: apdl + + ESEL,S,TYPE,,1 + + .. tab-item:: Python + :sync: key2 + + .. code:: python + + mapdl.esel("s", "type", "", 1) + mapdl.esel("s", "type", vmin=1) + None of these restrictions apply to commands run with the :func:`Mapdl.run() ` method. It might be easier to run some of these commands, such as ``"/SOLU"``: -.. code:: python +.. tab-set:: - mapdl.run("/SOLU") - mapdl.solve() + .. tab-item:: APDL + :sync: key1 -You can use the alternative: + .. code:: apdl -.. code:: python + /SOLU + + .. tab-item:: Python + :sync: key2 - mapdl.slashsolu() + .. code:: python + + # The next three functions are equivalent. Enter the solution processor. + mapdl.run("/SOLU") + mapdl.slashsolu() + mapdl.solution() + + +Running in non-interactive mode +------------------------------- Some commands can only be run non-interactively from within a script. PyMAPDL gets around this restriction by writing the commands @@ -66,60 +132,157 @@ method. Here is an example: mapdl.run("*VWRITE,LABEL(1),VALUE(1,1),VALUE(1,2),VALUE(1,3)") mapdl.run("(1X,A8,' ',F10.1,' ',F10.1,' ',1F5.3)") -Note that macros created within PyMAPDL (rather than loaded from -a file) do not appear to run correctly. For example, here is the macro -``DISP`` created using the ``*CREATE`` command within APDL: + +You can then view the final response of the non-interactive context with the +:attr:`Mapdl.last_response ` attribute. + +Using the :meth:`Mapdl.non_interactive() ` +method can also be useful to run commands on the server side without the interaction +of Python. This can speed up things greatly, but you should be aware of how +APDL works. An interesting discussion about speed comparison between PyMAPDL and APDL +can be found in `Speed comparison between PyMAPDL and APDL `_. + +You should use the +:meth:`Mapdl.non_interactive() ` method with caution. + +How the non-interactive context manager works +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :meth:`Mapdl.non_interactive() ` method is implemented +as a `context manager `_, which means that there are some actions +happening when entering and exit the context. +When entering the context, the :class:`Mapdl ` instance stops sending any APDL +command to the MAPDL instance. +Instead, it allocates a buffer for those APDL commands. +For each PyMAPDL command inside that context, PyMAPDL stores the equivalent MAPDL command +inside that buffer. +Right before exiting the context, PyMAPDL creates a text file with all these APDL commands, sends it to +the MAPDL instance, and runs it using the +:meth:`Mapdl.input() ` method. + + +For instance, this example code uses the :meth:`non_interactive context ` method to generate input for MAPDL: + +.. code:: python + + with mapdl.non_interactive: + mapdl.nsel("all") + mapdl.nsel("R", "LOC", "Z", 10) + +The preceding code generates this input for MAPDL: .. code:: apdl - ! SELECT NODES AT Z = 10 TO APPLY DISPLACEMENT - *CREATE,DISP + NSEL,ALL NSEL,R,LOC,Z,10 - D,ALL,UZ,ARG1 - NSEL,ALL - /OUT,SCRATCH - SOLVE - *END - ! Call the function - *USE,DISP,-.032 - *USE,DISP,-.05 - *USE,DISP,-.1 +This MAPLD input is executed with a :meth:`Mapdl.input() ` method call. -It should be written as follows: +Because of the non-interactive context not running all the commands until the end, +you might find issues interacting inside it, with Python for instance. +For example, running Python commands such as the +:meth:`Mapdl.get_array() ` method +inside the context can give you out-of-sync responses. +The following code snippet is a demonstration of this kind of problem: .. code:: python - def DISP( - ARG1="", - ARG2="", - ARG3="", - ARG4="", - ARG5="", - ARG6="", - ARG7="", - ARG8="", - ARG9="", - ARG10="", - ARG11="", - ARG12="", - ARG13="", - ARG14="", - ARG15="", - ARG16="", - ARG17="", - ARG18="", - ): - mapdl.nsel("R", "LOC", "Z", 10) # SELECT NODES AT Z = 10 TO APPLY DISPLACEMENT - mapdl.d("ALL", "UZ", ARG1) - mapdl.nsel("ALL") - mapdl.run("/OUT,SCRATCH") - mapdl.solve() + # Create some keypoints + mapdl.clear() + mapdl.k(1, 0, 0, 0) + mapdl.k(2, 1, 0, 0) + + with mapdl.non_interactive: + mapdl.k(3, 2, 0, 0) + klist_inside = mapdl.get_array("KP", item1="KLIST") + # Here is where PyMAPDL sends the commands to the MAPDL instance and execute 'mapdl.k(3,2,0,0)' (`K,3,2,0,0` + + klist_outside = mapdl.get_array("KP", item1="KLIST") + + assert klist_inside != klist_outside # Evaluates to true + +In the preceding script, the values obtained by the +:meth:`Mapdl.get_array() ` method are different: + +.. code:: pycon + >>> print(klist_inside) + array([1., 2.]) + >>> print(klist_outside) + array([1., 2., 3.]) - DISP(-0.032) - DISP(-0.05) - DISP(-0.1) +This is because the first :meth:`Mapdl.get_array() ` +method call is executed *before* the :meth:`Mapdl.k() ` method call. + +You should not retrieve any data in a Pythonic way from the MAPDL instance while using the +:meth:`non_interactive context ` method. +Being aware of this kind of behavior and how the :meth:`non_interactive context ` method +works is crucial for advanced usage of PyMAPDL. + + +MAPDL macros +------------ +Note that macros created within PyMAPDL (rather than loaded from +a file) do not appear to run correctly. For example, here is the ``DISP`` +macro created using the ``*CREATE`` command within APDL and within PyMAPDL: + + +.. tab-set:: + + .. tab-item:: APDL + :sync: key1 + + .. code:: apdl + + ! SELECT NODES AT Z = 10 TO APPLY DISPLACEMENT + *CREATE,DISP + NSEL,R,LOC,Z,10 + D,ALL,UZ,ARG1 + NSEL,ALL + /OUT,SCRATCH + SOLVE + *END + + ! Call the function + *USE,DISP,-.032 + *USE,DISP,-.05 + *USE,DISP,-.1 + + .. tab-item:: Python + :sync: key2 + + .. code:: python + + def DISP( + ARG1="", + ARG2="", + ARG3="", + ARG4="", + ARG5="", + ARG6="", + ARG7="", + ARG8="", + ARG9="", + ARG10="", + ARG11="", + ARG12="", + ARG13="", + ARG14="", + ARG15="", + ARG16="", + ARG17="", + ARG18="", + ): + mapdl.nsel("R", "LOC", "Z", 10) # SELECT NODES AT Z = 10 TO APPLY DISPLACEMENT + mapdl.d("ALL", "UZ", ARG1) + mapdl.nsel("ALL") + mapdl.run("/OUT,SCRATCH") + mapdl.solve() + + + DISP(-0.032) + DISP(-0.05) + DISP(-0.1) If you have an existing input file with a macro, you can convert it using the :func:`convert_script() ` @@ -133,7 +296,7 @@ method, setting``macros_as_functions=True``: Additional options when running commands -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +---------------------------------------- Commands can be run in ``mute`` or ``verbose`` mode, which allows you to suppress or print the output as it is being run for any MAPDL command. This can be especially helpful for long-running commands @@ -160,7 +323,7 @@ Run a command and stream its output while it is being run: Running several commands or an input file -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +----------------------------------------- You can run several MAPDL commands as a unified block using the :func:`Mapdl.input_strings() ` method. This is useful when using PyMAPDL with older MAPDL scripts. For example: @@ -226,73 +389,88 @@ Mechanical, you can run that with: Conditional statements and loops -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-------------------------------- APDL conditional statements such as ``*IF`` must be either implemented Pythonically or by using the :attr:`Mapdl.non_interactive ` attribute. For example: -.. code:: apdl - - *IF,ARG1,EQ,0,THEN - *GET,ARG4,NX,ARG2 ! RETRIEVE COORDINATE LOCATIONS OF BOTH NODES - *GET,ARG5,NY,ARG2 - *GET,ARG6,NZ,ARG2 - *GET,ARG7,NX,ARG3 - *GET,ARG8,NY,ARG3 - *GET,ARG9,NZ,ARG3 - *ELSE - *GET,ARG4,KX,ARG2 ! RETRIEVE COORDINATE LOCATIONS OF BOTH KEYPOINTS - *GET,ARG5,KY,ARG2 - *GET,ARG6,KZ,ARG2 - *GET,ARG7,KX,ARG3 - *GET,ARG8,KY,ARG3 - *GET,ARG9,KZ,ARG3 - *ENDIF - -This should be implemented as follows: - -.. code:: python - - with mapdl.non_interactive: - mapdl.run("*IF,ARG1,EQ,0,THEN") - mapdl.run("*GET,ARG4,NX,ARG2 ") # RETRIEVE COORDINATE LOCATIONS OF BOTH NODES - mapdl.run("*GET,ARG5,NY,ARG2") - mapdl.run("*GET,ARG6,NZ,ARG2") - mapdl.run("*GET,ARG7,NX,ARG3") - mapdl.run("*GET,ARG8,NY,ARG3") - mapdl.run("*GET,ARG9,NZ,ARG3") - mapdl.run("*ELSE") - mapdl.run( - "*GET,ARG4,KX,ARG2 " - ) # RETRIEVE COORDINATE LOCATIONS OF BOTH KEYPOINTS - mapdl.run("*GET,ARG5,KY,ARG2") - mapdl.run("*GET,ARG6,KZ,ARG2") - mapdl.run("*GET,ARG7,KX,ARG3") - mapdl.run("*GET,ARG8,KY,ARG3") - mapdl.run("*GET,ARG9,KZ,ARG3") - mapdl.run("*ENDIF") - -Or, implemented Pythonically as follows: +.. tab-set:: + + .. tab-item:: APDL + :sync: key1 + + .. code:: apdl + + *IF,ARG1,EQ,0,THEN + *GET,ARG4,NX,ARG2 ! RETRIEVE COORDINATE LOCATIONS OF BOTH NODES + *GET,ARG5,NY,ARG2 + *GET,ARG6,NZ,ARG2 + *GET,ARG7,NX,ARG3 + *GET,ARG8,NY,ARG3 + *GET,ARG9,NZ,ARG3 + *ELSE + *GET,ARG4,KX,ARG2 ! RETRIEVE COORDINATE LOCATIONS OF BOTH KEYPOINTS + *GET,ARG5,KY,ARG2 + *GET,ARG6,KZ,ARG2 + *GET,ARG7,KX,ARG3 + *GET,ARG8,KY,ARG3 + *GET,ARG9,KZ,ARG3 + *ENDIF + + .. tab-item:: Python-Non interactive + :sync: key3 + + .. code:: python + + with mapdl.non_interactive: + mapdl.run("*IF,ARG1,EQ,0,THEN") + mapdl.run("*GET,ARG4,NX,ARG2 ") # RETRIEVE COORDINATE LOCATIONS OF BOTH NODES + mapdl.run("*GET,ARG5,NY,ARG2") + mapdl.run("*GET,ARG6,NZ,ARG2") + mapdl.run("*GET,ARG7,NX,ARG3") + mapdl.run("*GET,ARG8,NY,ARG3") + mapdl.run("*GET,ARG9,NZ,ARG3") + mapdl.run("*ELSE") + mapdl.run( + "*GET,ARG4,KX,ARG2 " + ) # RETRIEVE COORDINATE LOCATIONS OF BOTH KEYPOINTS + mapdl.run("*GET,ARG5,KY,ARG2") + mapdl.run("*GET,ARG6,KZ,ARG2") + mapdl.run("*GET,ARG7,KX,ARG3") + mapdl.run("*GET,ARG8,KY,ARG3") + mapdl.run("*GET,ARG9,KZ,ARG3") + mapdl.run("*ENDIF") + + + .. tab-item:: Python + :sync: key2 + + .. code:: python + + if ARG1 == 0: + mapdl.get(ARG4, "NX", ARG2) # RETRIEVE COORDINATE LOCATIONS OF BOTH NODES + mapdl.get(ARG5, "NY", ARG2) + mapdl.get(ARG6, "NZ", ARG2) + mapdl.get(ARG7, "NX", ARG3) + mapdl.get(ARG8, "NY", ARG3) + mapdl.get(ARG9, "NZ", ARG3) + else: + mapdl.get(ARG4, "KX", ARG2) # RETRIEVE COORDINATE LOCATIONS OF BOTH KEYPOINTS + mapdl.get(ARG5, "KY", ARG2) + mapdl.get(ARG6, "KZ", ARG2) + mapdl.get(ARG7, "KX", ARG3) + mapdl.get(ARG8, "KY", ARG3) + mapdl.get(ARG9, "KZ", ARG3) + +The values of ``ARGX`` parameters are not retrieved from the MAPDL instance. +Hence you cannot use those arguments in Python code unless you use the following commands: .. code:: python - # MAPDL parameters can be obtained using load_parameters - if ARG1 == 0: - mapdl.run("*GET,ARG4,NX,ARG2 ") # RETRIEVE COORDINATE LOCATIONS OF BOTH NODES - mapdl.run("*GET,ARG5,NY,ARG2") - mapdl.run("*GET,ARG6,NZ,ARG2") - mapdl.run("*GET,ARG7,NX,ARG3") - mapdl.run("*GET,ARG8,NY,ARG3") - mapdl.run("*GET,ARG9,NZ,ARG3") - else: - mapdl.run( - "*GET,ARG4,KX,ARG2 " - ) # RETRIEVE COORDINATE LOCATIONS OF BOTH KEYPOINTS - mapdl.run("*GET,ARG5,KY,ARG2") - mapdl.run("*GET,ARG6,KZ,ARG2") - mapdl.run("*GET,ARG7,KX,ARG3") - mapdl.run("*GET,ARG8,KY,ARG3") - mapdl.run("*GET,ARG9,KZ,ARG3") + ARG4 = mapdl.parameters["ARG4"] + ARG5 = mapdl.parameters["ARG5"] + # ... + # etc APDL loops using ``*DO`` or ``*DOWHILE`` should also be implemented using the :attr:`Mapdl.non_interactive ` @@ -300,7 +478,7 @@ attribute or implemented Pythonically. Warnings and errors -~~~~~~~~~~~~~~~~~~~ +------------------- Errors are handled Pythonically. For example: .. code:: python @@ -340,15 +518,15 @@ example: Prompts -~~~~~~~ +------- Prompts from MAPDL automatically continued as if MAPDL is in batch mode. Commands requiring user input, such as the -:func:`Mapdl.vwrite() ` method fail +:meth:`Mapdl.vwrite() ` method, fail and must be entered in non-interactively. APDL command logging --------------------- +==================== While ``ansys-mapdl-core`` is designed to make it easier to control an APDL session by calling it using Python, it might be necessary to call MAPDL again using an input file generated from a PyMAPDL script. This @@ -372,7 +550,7 @@ For example: This code writes the following to the ``"apdl.log"`` file: -.. code:: text +.. code:: apdl /PREP7, K,1,0,0,0 @@ -384,14 +562,14 @@ This allows for the translation of a Python script to an APDL script except for conditional statements, loops, or functions. Use the ``lgwrite`` method -~~~~~~~~~~~~~~~~~~~~~~~~~~ +-------------------------- Alternatively, if you only want the database command output, you can use the :func:`Mapdl.lgwrite ` method to write the entire database command log to a file. Interactive breakpoint ----------------------- +====================== In most circumstances, it is necessary or preferable to open up the MAPDL GUI. The :class:`Mapdl ` class has the :func:`Mapdl.open_gui() ` method, which @@ -440,8 +618,8 @@ changes made in the GUI affect the script. You can experiment in the GUI, and the script is left unaffected. -Run a batch ------------- +Run a batch job +=============== Instead of running a MAPDL batch by calling MAPDL with an input file, you can instead define a function that runs MAPDL. This example runs a mesh convergence study based on the maximum stress of a cylinder @@ -587,7 +765,8 @@ Here is the output from the script: Chain commands in MAPDL ------------------------ +======================= + MAPDL permits several commands on one line by using the separation character ``"$"``. This can be utilized within PyMAPDL to effectively chain several commands together and send them to MAPDL for execution @@ -630,7 +809,7 @@ the chained commands with the Sending arrays to MAPDL ------------------------ +======================= You can send ``numpy`` arrays or Python lists directly to MAPDL using the :attr:`Mapdl.Parameters ` attribute. This is far more efficient than individually sending parameters to @@ -663,7 +842,7 @@ was a Python dictionary: Download a remote MAPDL file -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +---------------------------- When running MAPDL in gRPC mode, remote MAPDL files can be listed and downloaded using the :class:`Mapdl ` class with the :func:`Mapdl.download() ` @@ -713,7 +892,7 @@ Or, filter by extensions as shown in this example: Upload a local MAPDL file -~~~~~~~~~~~~~~~~~~~~~~~~~ +------------------------- You can upload a local MAPDL file as the remote MAPDL instance with the :func:`Mapdl.upload() ` method: @@ -732,7 +911,7 @@ You can upload a local MAPDL file as the remote MAPDL instance with the Unsupported MAPDL commands and other considerations ---------------------------------------------------- +=================================================== Most MAPDL commands have been mapped Pythonically into their equivalent methods. Some commands, however, are not supported because either they are not applicable to an interactive session or they require @@ -743,7 +922,7 @@ handled on the MAPDL server. .. _ref_unsupported_commands: Unavailable commands -~~~~~~~~~~~~~~~~~~~~ +-------------------- Some commands are unavailable in PyMAPDL for a variety of reasons. Some of these commands do not make sense in a Python context. @@ -858,7 +1037,7 @@ method. The results should be same as running them in a normal batch MAPDL sessi .. _ref_unsupported_interactive_commands: Unsupported "interactive" commands -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +---------------------------------- The following commands can be only run in non-interactive mode (inside a :attr:`Mapdl.non_interactive ` block or @@ -888,7 +1067,7 @@ are unsupported. Environment variables ---------------------- +===================== There are several PyMAPDL-specific environment variables that can be used to control the behavior or launching of PyMAPDL and MAPDL. diff --git a/src/ansys/mapdl/core/parameters.py b/src/ansys/mapdl/core/parameters.py index 3b7487184b..0d8053e94d 100644 --- a/src/ansys/mapdl/core/parameters.py +++ b/src/ansys/mapdl/core/parameters.py @@ -292,6 +292,10 @@ def type(self) -> int: @supress_logging def _parm(self): """Current MAPDL parameters""" + if self._mapdl._store_commands: + # in interactive mode + return {} + params = interp_star_status( self._mapdl.starstatus(avoid_non_interactive=True, mute=False) ) @@ -326,8 +330,15 @@ def __repr__(self): def __getitem__(self, key): """Return a parameter""" + if self._mapdl._store_commands: + raise MapdlRuntimeError( + "Cannot use `mapdl.parameters` to retrieve parameters when in " + "`non_interactive` mode. " + "Exit `non_interactive` mode before using this method." + ) + if not isinstance(key, str): - raise TypeError("Parameter name must be a string") + raise TypeError("Parameter name must be a string.") key = key.upper() with self.full_parameters_output: diff --git a/tests/test_parameters.py b/tests/test_parameters.py index 85b187c8a9..2516f3a64f 100644 --- a/tests/test_parameters.py +++ b/tests/test_parameters.py @@ -427,3 +427,15 @@ def test_parameter_contains(mapdl, cleared): def test_non_existing_parameter(mapdl, cleared): with pytest.raises(KeyError): mapdl.parameters["A"] + + +def test_non_interactive(mapdl): + mapdl.parameters["asdf"] = 2 + with pytest.raises(MapdlRuntimeError): + with mapdl.non_interactive: + par = mapdl.parameters["asdf"] + + with mapdl.non_interactive: + mapdl.parameters["qwer"] = 3 + + assert mapdl.parameters["qwer"] == 3 From 6b6d3ce1652a998e8dc67894a4f87c10a6b4303f Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Wed, 22 Nov 2023 20:47:47 +0100 Subject: [PATCH 27/30] Small changes (#2523) * fixing reference * fixing bat file internal links * Fixing vale runtime issue --- doc/make.bat | 5 ++++- doc/source/user_guide/pool.rst | 11 ++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/doc/make.bat b/doc/make.bat index bdf99fb5df..588240614e 100644 --- a/doc/make.bat +++ b/doc/make.bat @@ -13,8 +13,8 @@ set LINKCHECKDIR=\%BUILDDIR%\linkcheck if "%1" == "" goto help if "%1" == "clean" goto clean -if "%1" == "clean-all" goto clean-all if "%1" == "clean-examples" goto clean-examples +if "%1" == "clean-except-examples" goto clean-except-examples if "%1" == "linkcheck" goto linkcheck @@ -35,12 +35,14 @@ if errorlevel 9009 ( goto end :clean-except-examples +echo Cleaning everything except examples rmdir /s /q %BUILDDIR% > /NUL 2>&1 rmdir /s /q images/auto-generated > /NUL 2>&1 for /d /r %SOURCEDIR% %%d in (_autosummary) do @if exist "%%d" rmdir /s /q "%%d" goto end :clean +echo Cleaning everything rmdir /s /q %BUILDDIR% > /NUL 2>&1 rmdir /s /q source\examples\gallery_examples > /NUL 2>&1 for /d /r %SOURCEDIR% %%d in (_autosummary) do @if exist "%%d" rmdir /s /q "%%d" @@ -48,6 +50,7 @@ rmdir /s /q images/auto-generated > /NUL 2>&1 goto end :clean-examples +echo Cleaning examples rmdir /s /q source\examples\gallery_examples > /NUL 2>&1 goto end diff --git a/doc/source/user_guide/pool.rst b/doc/source/user_guide/pool.rst index efa975b1dc..432bed36b5 100644 --- a/doc/source/user_guide/pool.rst +++ b/doc/source/user_guide/pool.rst @@ -2,11 +2,12 @@ Create a pool of MAPDL instances ================================ -PyMAPDL contains the :class:`LocalMapdlPool ` -class to simplify creating multiple local instances of the -:class:`Mapdl ` class for batch processing. -This can be used for the batch processing of a set of input files, -convergence analysis, or other batch related processes. +PyMAPDL contains the :class:`LocalMapdlPool ` +class to simplify creating multiple local instances of the +:class:`Mapdl ` +class for batch processing. This can be used for the batch processing of a +set of input files, convergence analysis, or other batch related +processes. This code creates a pool: From 68a3be42516964a06a0bf9f5d00a2b3097e1e982 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Thu, 23 Nov 2023 11:09:39 +0100 Subject: [PATCH 28/30] Adding workflow to delete untagged images in MAPDL package (#2524) --- .github/workflows/docker_clean_untagged.yml | 29 +++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .github/workflows/docker_clean_untagged.yml diff --git a/.github/workflows/docker_clean_untagged.yml b/.github/workflows/docker_clean_untagged.yml new file mode 100644 index 0000000000..570418c642 --- /dev/null +++ b/.github/workflows/docker_clean_untagged.yml @@ -0,0 +1,29 @@ +name: Docker images - Cleanup +on: + workflow_dispatch: + schedule: # UTC at 0200 + - cron: "0 2 * * *" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: write + packages: write + +jobs: + cleanup: + name: Cleaning unnecessary packages + runs-on: ubuntu-latest + env: + PACKAGE_DELETION_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + steps: + + - name: "Perform versions cleanup - except certain tags" + uses: ansys/actions/hk-package-clean-untagged@v4 + with: + package-name: 'mapdl' + token: ${{ secrets.GITHUB_TOKEN }} + allow-last-days: 5 \ No newline at end of file From 7733aba9b3f7fc1e37b1d3e61e08901f88709604 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Thu, 23 Nov 2023 14:17:00 +0100 Subject: [PATCH 29/30] Adding codeowner file (#2526) --- CODEOWNERS | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 CODEOWNERS diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000000..7b9b2f49b0 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,7 @@ +# Repository codeowners +# +# Reference: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners + +/.ci/ @ansys/pymapdl-maintainers +/.github/ @ansys/pymapdl-maintainers +pyproject.toml @ansys/pymapdl-maintainers From 9cc780cf552cf0fdb1d4ba9a04c385cd84c925d7 Mon Sep 17 00:00:00 2001 From: German <28149841+germa89@users.noreply.github.com> Date: Thu, 23 Nov 2023 14:30:03 +0100 Subject: [PATCH 30/30] Update contributing file (#2527) --- CONTRIBUTING.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dabe21a0c7..1cda557aba 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,9 @@ a useful tool for all users. As such, we welcome and encourage any questions or submissions to this repository. -For contributing to this project, please refer to the [PyAnsys Developer's Guide]. -Further information about contributing to PyMAPDL can be found in [Contributing](https://mapdl.docs.pyansys.com/version/stable/getting_started/contribution.html). +Information about contributing to PyMAPDL can be found in +[Contributing](https://mapdl.docs.pyansys.com/version/stable/getting_started/contribution.html). + +For further information about contributing to PyAnsys projects, +refer to the [PyAnsys Developer's Guide](https://dev.docs.pyansys.com/). -[PyAnsys Developer's Guide]: https://dev.docs.pyansys.com/