From caf20d30c5437711c4a9a4c2152998c0f43097ac Mon Sep 17 00:00:00 2001 From: German Date: Tue, 17 Oct 2023 17:40:05 +0200 Subject: [PATCH 01/70] first approach --- src/ansys/mapdl/core/convert.py | 18 +++++++++++++++-- tests/test_convert.py | 35 ++++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index 0c8530a468..8e32ad822e 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -454,6 +454,7 @@ def __init__( self.cleanup_output = cleanup_output self._header = header self.print_com = print_com + self.verification_example = False self.write_header() if self._add_imports: @@ -623,6 +624,8 @@ def translate_line(self, line): line = ",".join(line_[ind:][::-1]) + line_with_trailing_commas = line + # remove trailing comma line = line[:-1] if line[-1] == "," else line line_upper = line.upper() @@ -640,11 +643,19 @@ def translate_line(self, line): self.store_command("com", [line]) return + if cmd_caps_short == "/VER": + self.verification_example = True + if cmd_caps_short == "/COM": # It is a comment self.store_command("com", [line[5:]]) return + if cmd_caps_short == "C***": + # It is an old style comment + self.store_command("com", [line[5:]]) + return + if cmd_caps == "*DO": self.start_non_interactive() self.store_run_command(line) @@ -669,7 +680,7 @@ def translate_line(self, line): if cmd_caps == "/VERIFY": self.store_run_command("FINISH") self.store_run_command(line) - self.store_run_command("/PREP7") + self.store_command("prep7", "") return if cmd_caps_short == "*REP": @@ -686,7 +697,10 @@ def translate_line(self, line): self.end_non_interactive() return - if cmd_caps_short in COMMANDS_TO_NOT_BE_CONVERTED: + if ( + cmd_caps_short in COMMANDS_TO_NOT_BE_CONVERTED + and ",," in line_with_trailing_commas + ): self.store_run_command(line) return diff --git a/tests/test_convert.py b/tests/test_convert.py index bfaceae501..4aabf100e9 100644 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -318,9 +318,16 @@ def test_header(): assert '"""My header"""' in convert_apdl_block("/com", header="My header") -def test_com(): - converted_output = convert_apdl_block( +@pytest.mark.parametrize( + "cmd", + [ "/com, this is a comment !inline comment!", + "C***, this is a comment !inline comment!", + ], +) +def test_com(cmd): + converted_output = convert_apdl_block( + cmd, header=False, add_imports=False, ) @@ -362,11 +369,33 @@ def test_repeat(): @pytest.mark.parametrize("cmd", COMMANDS_TO_NOT_BE_CONVERTED) def test_commands_to_not_be_converted(cmd): - assert f'mapdl.run("{cmd}")' in convert_apdl_block( + # Checking trailing commas does not avoid conversion + # assert f'mapdl.run("{cmd}")' not in convert_apdl_block( + # cmd+",,", header=False, add_imports=False + # ) + # Checking empty arguments avoid conversion + assert f'mapdl.run("{cmd},,OTHER_ARG")' in convert_apdl_block( + cmd + ",,OTHER_ARG", header=False, add_imports=False + ) + + # Checking default conversion + assert f'mapdl.run("{cmd}")' not in convert_apdl_block( cmd, header=False, add_imports=False ) +def test_commands_with_empty_arguments(): + cmd = """ANTYPE,STATIC ! STATIC ANALYSIS +ANTYPE,STATIC,,NON_EMPTY_ARGUMENT + +ANTYPE,STATIC,,,""" + pycmd = """mapdl.antype("STATIC") # STATIC ANALYSIS +mapdl.run("ANTYPE,STATIC,,NON_EMPTY_ARGUMENT") +mapdl.antype("STATIC")""" + + assert pycmd in convert_apdl_block(cmd, header=False, add_imports=False) + + @pytest.mark.parametrize("ending", ["\n", "\r\n"]) def test_detect_line_ending(ending): assert ending in convert_apdl_block( From be26a1f7835209b8af74bb23a6f51c792d5164b9 Mon Sep 17 00:00:00 2001 From: German Date: Wed, 18 Oct 2023 15:17:29 +0200 Subject: [PATCH 02/70] Being more exigent on the commands with empty arguments. Avoiding issue `/out,scratch`. --- src/ansys/mapdl/core/convert.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index 8e32ad822e..b6a8eb9660 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -66,7 +66,6 @@ COMMANDS_TO_NOT_BE_CONVERTED = [] -COMMANDS_TO_NOT_BE_CONVERTED.extend(COMMANDS_WITH_EMPTY_ARGS) def convert_script( @@ -667,8 +666,11 @@ def translate_line(self, line): return if self.output_to_file(line): - self.start_non_interactive() - self.store_run_command(line) + if self.verification_example and "SCRATCH" in line.upper(): + self.store_command("com", [line]) + else: + self.start_non_interactive() + self.store_run_command(line) return if self.output_to_default(line): @@ -697,13 +699,19 @@ def translate_line(self, line): self.end_non_interactive() return + # Skipping conversion if command has empty arguments and there is ",," in the call if ( - cmd_caps_short in COMMANDS_TO_NOT_BE_CONVERTED + cmd_caps_short in COMMANDS_WITH_EMPTY_ARGS and ",," in line_with_trailing_commas ): self.store_run_command(line) return + # Skipping commands to not be converted + if cmd_caps_short in COMMANDS_TO_NOT_BE_CONVERTED: + self.store_run_command(line) + return + if cmd_caps_short == "/TIT": # /TITLE parameters = line.split(",")[1:] return self.store_command("title", ["".join(parameters).strip()]) From a0c70eb7a4db6c9019eb59553d85ee26178979cb Mon Sep 17 00:00:00 2001 From: German Date: Wed, 18 Oct 2023 15:32:29 +0200 Subject: [PATCH 03/70] Adding tests to previous commit --- tests/test_convert.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/tests/test_convert.py b/tests/test_convert.py index 4aabf100e9..59aee15278 100644 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -4,11 +4,7 @@ from ansys.mapdl import core as pymapdl from ansys.mapdl.core import examples -from ansys.mapdl.core.convert import ( - COMMANDS_TO_NOT_BE_CONVERTED, - FileTranslator, - convert_apdl_block, -) +from ansys.mapdl.core.convert import FileTranslator, convert_apdl_block nblock = """nblock,3,,326253 (1i9,3e20.9e3) @@ -367,14 +363,23 @@ def test_repeat(): ) -@pytest.mark.parametrize("cmd", COMMANDS_TO_NOT_BE_CONVERTED) +@pytest.mark.parametrize( + "cmd", + [ + "/PMORE", # "/PMORE, + "ANTYPE", # ANTYPE, + "ASBL", # ASBL, + "ATAN", # ATAN, + ], +) def test_commands_to_not_be_converted(cmd): # Checking trailing commas does not avoid conversion - # assert f'mapdl.run("{cmd}")' not in convert_apdl_block( - # cmd+",,", header=False, add_imports=False - # ) + assert f'mapdl.run("{cmd}")' not in convert_apdl_block( + cmd + ",,", header=False, add_imports=False + ) + # Checking empty arguments avoid conversion - assert f'mapdl.run("{cmd},,OTHER_ARG")' in convert_apdl_block( + assert f'mapdl.run("{cmd.upper()},,OTHER_ARG")' in convert_apdl_block( cmd + ",,OTHER_ARG", header=False, add_imports=False ) From c3eebc46a1048f6c12c599ab007da2a1bd01c33f Mon Sep 17 00:00:00 2001 From: German Date: Wed, 18 Oct 2023 15:43:44 +0200 Subject: [PATCH 04/70] Adding `use_vtk` argument --- src/ansys/mapdl/core/convert.py | 32 ++++++++++++++++++++++++++------ tests/test_convert.py | 16 ++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index b6a8eb9660..b7f2185d7b 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -84,6 +84,7 @@ def convert_script( header=True, print_com=True, only_commands=False, + use_vtk=None, ): """Converts an ANSYS input file to a python PyMAPDL script. @@ -155,6 +156,10 @@ def convert_script( and exit commands are NOT included (``auto_exit=False``). Overrides ``header``, ``add_imports`` and ``auto_exit``. + use_vtk : bool, optional + It sets the `mapdl.use_vtk` argument equals True or False depending on + this value. + Returns ------- list @@ -210,6 +215,7 @@ def convert_script( header=header, print_com=print_com, only_commands=only_commands, + use_vtk=use_vtk, ) translator.save(filename_out) @@ -231,6 +237,7 @@ def convert_apdl_block( header=True, print_com=True, only_commands=False, + use_vtk=None, ): """Converts an ANSYS input string to a python PyMAPDL string. @@ -298,6 +305,10 @@ def convert_apdl_block( and exit commands are NOT included (``auto_exit=False``). Overrides ``header``, ``add_imports`` and ``auto_exit``. + use_vtk : bool, optional + It sets the `mapdl.use_vtk` argument equals True or False depending on + this value. + Returns ------- list @@ -334,6 +345,7 @@ def convert_apdl_block( header=header, print_com=print_com, only_commands=only_commands, + use_vtk=use_vtk, ) if isinstance(apdl_strings, str): @@ -356,6 +368,7 @@ def _convert( header=True, print_com=True, only_commands=False, + use_vtk=None, ): if only_commands: auto_exit = False @@ -374,6 +387,7 @@ def _convert( cleanup_output=cleanup_output, header=header, print_com=print_com, + use_vtk=use_vtk, ) if isinstance(apdl_strings, str): @@ -436,6 +450,7 @@ def __init__( cleanup_output=True, header=True, print_com=True, + use_vtk=None, ): self._non_interactive_level = 0 self.lines = Lines(mute=not show_log) @@ -454,6 +469,7 @@ def __init__( self._header = header self.print_com = print_com self.verification_example = False + self.use_vtk = use_vtk self.write_header() if self._add_imports: @@ -553,16 +569,20 @@ def initialize_mapdl_object(self, loglevel, exec_file): core_module = "ansys.mapdl.core" # shouldn't change self.lines.append(f"from {core_module} import launch_mapdl") + mapdl_arguments = [f'loglevel="{loglevel}"'] + if exec_file: - exec_file_parameter = f'exec_file="{exec_file}", ' - else: - exec_file_parameter = "" + mapdl_arguments.append(f'exec_file="{exec_file}"') if self.print_com: - line = f'{self.obj_name} = launch_mapdl({exec_file_parameter}loglevel="{loglevel}", print_com=True)\n' - else: - line = f'{self.obj_name} = launch_mapdl({exec_file_parameter}loglevel="{loglevel}")\n' + mapdl_arguments.append("print_com=True") + + if self.use_vtk is not None: + mapdl_arguments.append(f"use_vtk={bool(self.use_vtk)}") + + line = f'{self.obj_name} = launch_mapdl({", ".join(mapdl_arguments)})' self.lines.append(line) + self.lines.append(f"{self.obj_name}.clear() # Clearing session") @property def line_ending(self): diff --git a/tests/test_convert.py b/tests/test_convert.py index 59aee15278..d115c290a6 100644 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -461,6 +461,22 @@ def test_only_commands(): assert "mapdl.exit" not in output +@pytest.mark.parametrize("vtk", [None, True, False]) +def test_use_vtk(vtk): + output = convert_apdl_block( + "/view,1,1,1", + only_commands=False, + add_imports=True, + use_vtk=vtk, + ) + assert "mapdl.view(1, 1, 1)" in output + assert "launch_mapdl" in output + if vtk is None: + assert "use_vtk" not in output + else: + assert f"use_vtk={vtk}" in output + + @pytest.mark.parametrize( "parameters", [ From d5c7fdf01428774f57a0d80bc3054783c2ce2be3 Mon Sep 17 00:00:00 2001 From: German Date: Wed, 18 Oct 2023 15:48:13 +0200 Subject: [PATCH 05/70] Adding clear_at_start argument --- src/ansys/mapdl/core/convert.py | 18 +++++++++++++++++- tests/test_convert.py | 16 ++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index b7f2185d7b..02bf053c09 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -85,6 +85,7 @@ def convert_script( print_com=True, only_commands=False, use_vtk=None, + clear_at_start=False, ): """Converts an ANSYS input file to a python PyMAPDL script. @@ -160,6 +161,9 @@ def convert_script( It sets the `mapdl.use_vtk` argument equals True or False depending on this value. + clear_at_start : bool, optional + Add a `mapdl.clear()` after the Mapdl object initialization. + Returns ------- list @@ -216,6 +220,7 @@ def convert_script( print_com=print_com, only_commands=only_commands, use_vtk=use_vtk, + clear_at_start=clear_at_start, ) translator.save(filename_out) @@ -238,6 +243,7 @@ def convert_apdl_block( print_com=True, only_commands=False, use_vtk=None, + clear_at_start=False, ): """Converts an ANSYS input string to a python PyMAPDL string. @@ -309,6 +315,9 @@ def convert_apdl_block( It sets the `mapdl.use_vtk` argument equals True or False depending on this value. + clear_at_start : bool, optional + Add a `mapdl.clear()` after the Mapdl object initialization. + Returns ------- list @@ -346,6 +355,7 @@ def convert_apdl_block( print_com=print_com, only_commands=only_commands, use_vtk=use_vtk, + clear_at_start=clear_at_start, ) if isinstance(apdl_strings, str): @@ -369,6 +379,7 @@ def _convert( print_com=True, only_commands=False, use_vtk=None, + clear_at_start=False, ): if only_commands: auto_exit = False @@ -388,6 +399,7 @@ def _convert( header=header, print_com=print_com, use_vtk=use_vtk, + clear_at_start=clear_at_start, ) if isinstance(apdl_strings, str): @@ -451,6 +463,7 @@ def __init__( header=True, print_com=True, use_vtk=None, + clear_at_start=False, ): self._non_interactive_level = 0 self.lines = Lines(mute=not show_log) @@ -470,6 +483,7 @@ def __init__( self.print_com = print_com self.verification_example = False self.use_vtk = use_vtk + self.clear_at_start = clear_at_start self.write_header() if self._add_imports: @@ -582,7 +596,9 @@ def initialize_mapdl_object(self, loglevel, exec_file): line = f'{self.obj_name} = launch_mapdl({", ".join(mapdl_arguments)})' self.lines.append(line) - self.lines.append(f"{self.obj_name}.clear() # Clearing session") + + if self.clear_at_start: + self.lines.append(f"{self.obj_name}.clear() # Clearing session") @property def line_ending(self): diff --git a/tests/test_convert.py b/tests/test_convert.py index d115c290a6..af18edf9a5 100644 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -477,6 +477,22 @@ def test_use_vtk(vtk): assert f"use_vtk={vtk}" in output +@pytest.mark.parametrize("clear_at_start", [None, True, False]) +def test_clear_at_start(clear_at_start): + output = convert_apdl_block( + "/view,1,1,1", + only_commands=False, + add_imports=True, + clear_at_start=clear_at_start, + ) + assert "mapdl.view(1, 1, 1)" in output + assert "launch_mapdl" in output + if clear_at_start: + assert "mapdl.clear()" in output + else: + assert "mapdl.clear()" not in output + + @pytest.mark.parametrize( "parameters", [ From 7060874c10c5dd27eec2871ecf9182624be8b309 Mon Sep 17 00:00:00 2001 From: German Date: Wed, 18 Oct 2023 15:57:08 +0200 Subject: [PATCH 06/70] Commenting better /out,scratch --- src/ansys/mapdl/core/convert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index 02bf053c09..02550c4f3e 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -703,7 +703,7 @@ def translate_line(self, line): if self.output_to_file(line): if self.verification_example and "SCRATCH" in line.upper(): - self.store_command("com", [line]) + self.store_command("com", [f"Skipping: {line}"]) else: self.start_non_interactive() self.store_run_command(line) From 2a03642db54778924115b39c9a70023245d793d3 Mon Sep 17 00:00:00 2001 From: German Date: Wed, 18 Oct 2023 17:55:36 +0200 Subject: [PATCH 07/70] Avoiding cmplot conversion Improving arguments parsing --- src/ansys/mapdl/core/convert.py | 30 ++++++++++++++++++++++++++++-- tests/test_convert.py | 6 ++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index 02550c4f3e..dfe379f929 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -65,7 +65,9 @@ ] -COMMANDS_TO_NOT_BE_CONVERTED = [] +COMMANDS_TO_NOT_BE_CONVERTED = [ + "CMPL" # CMPLOT default behaviour does not match the `mapdl.cmplot`'s at the moemnt +] def convert_script( @@ -668,7 +670,7 @@ def translate_line(self, line): cmd_caps = line.split(",")[0].upper() cmd_caps_short = cmd_caps[:4] - items = line.split(",") + items = self._get_items(line) if cmd_caps_short in ["SOLV", "LSSO"] and self._comment_solve: self.store_command( @@ -1059,6 +1061,30 @@ def output_to_default(self, line): return False + def _get_items(self, line_): + """Parse the line items (comma separated elements) but ignoring the ones inside parenthesis, or brackets""" + + parenthesis_count = 0 + + items = [] + begining_substring = 0 + + for ind, each_char in enumerate(line_): + if each_char in ["(", "[", "{"]: + parenthesis_count += 1 + + if each_char == "," and parenthesis_count == 0: + items.append(line_[begining_substring:ind]) + begining_substring = ind + 1 + + if ind == len(line_) - 1: # reaching ending of line + items.append(line_[begining_substring : ind + 1]) + + if each_char in [")", "]", "}"]: + parenthesis_count -= 1 + + return items + import click diff --git a/tests/test_convert.py b/tests/test_convert.py index af18edf9a5..0354fc60ee 100644 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -518,6 +518,12 @@ def test_convert_star_slash(parameters): assert convert_apdl_block(parameters[0], only_commands=True) == parameters[1] +def test_parsing_items(): + cmd = "VGET,VALUE7(2,2),2,7E-2" + conv_cmd = convert_apdl_block(cmd, only_commands=True) + assert 'mapdl.vget("VALUE7(2,2)", 2, 7E-2)' in conv_cmd + + ## CLI testing From 72020e4551b3aa15db02237d1e985b07f77915ba Mon Sep 17 00:00:00 2001 From: German Date: Wed, 18 Oct 2023 18:27:19 +0200 Subject: [PATCH 08/70] Supporting macros calls --- src/ansys/mapdl/core/convert.py | 13 +++++++++++++ tests/test_convert.py | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index dfe379f929..e3ad0fe62f 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -486,6 +486,7 @@ def __init__( self.verification_example = False self.use_vtk = use_vtk self.clear_at_start = clear_at_start + self.macros_names = [] self.write_header() if self._add_imports: @@ -770,12 +771,18 @@ def translate_line(self, line): return if cmd_caps_short == "*CRE": # creating a function + self.macros_names.append(items[1]) if self.macros_as_functions: self.start_function(items[1].strip()) return else: self.start_non_interactive() + if items[0] in self.macros_names: + # We are calling the function/macro created before. + self.store_python_command(f"{items[0]}()") + return + if cmd_caps == "/PREP7": return self.store_command("prep7", []) @@ -903,10 +910,12 @@ def start_function(self, func_name): func_name, ", ".join(["ARG%d=''" % i for i in range(1, 7)]), ) + line += "\n" line += "%s%s," % ( spacing, ", ".join(["ARG%d=''" % i for i in range(7, 13)]), ) + line += "\n" line += "%s%s):" % ( spacing, ", ".join(["ARG%d=''" % i for i in range(13, 19)]), @@ -970,6 +979,10 @@ def store_empty_line(self): """Stores an empty line""" self.lines.append("") + def store_python_command(self, command): + line = f"{self.indent}{command}" + self.lines.append(line) + def store_command(self, function, parameters): """Stores a valid pyansys function with parameters""" parsed_parameters = [] diff --git a/tests/test_convert.py b/tests/test_convert.py index 0354fc60ee..a4e5aa6306 100644 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -524,6 +524,19 @@ def test_parsing_items(): assert 'mapdl.vget("VALUE7(2,2)", 2, 7E-2)' in conv_cmd +def test_macros_call(): + cmd = """ +*create,myfunc +/prep7 +*end +myfunc +""" + conv_cmd = convert_apdl_block(cmd, only_commands=True) + assert "mapdl.prep7()" in conv_cmd + assert "def myfunc(" in conv_cmd + assert "myfunc()" in conv_cmd + + ## CLI testing From bbc03ddd9ec520d321c3e66f6a2f66deb334c84b Mon Sep 17 00:00:00 2001 From: German Date: Wed, 18 Oct 2023 18:27:39 +0200 Subject: [PATCH 09/70] Fixing expand arguments --- .../core/_commands/solution/analysis_options.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/ansys/mapdl/core/_commands/solution/analysis_options.py b/src/ansys/mapdl/core/_commands/solution/analysis_options.py index 585c9b42ea..effa873087 100644 --- a/src/ansys/mapdl/core/_commands/solution/analysis_options.py +++ b/src/ansys/mapdl/core/_commands/solution/analysis_options.py @@ -2016,7 +2016,7 @@ def essolv( command = f"ESSOLV,{electit},{strutit},{dimn},{morphopt},{mcomp},{xcomp},{electol},{strutol},{mxloop},,{ruseky},{restky},{eiscomp}" return self.run(command, **kwargs) - def expass(self, key="", **kwargs): + def expass(self, key="", keystat="", **kwargs): """Specifies an expansion pass of an analysis. APDL Command: EXPASS @@ -2025,10 +2025,13 @@ def expass(self, key="", **kwargs): ---------- key Expansion pass key: + * OFF - No expansion pass will be performed (default). + * ON - An expansion pass will be performed. - OFF - No expansion pass will be performed (default). - - ON - An expansion pass will be performed. + keystat + Static correction vectors key: + * ON - Include static correction vectors in the expanded displacements (default). + * OFF - Do not include static correction vectors in the expanded displacements. Notes ----- @@ -2040,7 +2043,7 @@ def expass(self, key="", **kwargs): This command is also valid in PREP7. """ - command = f"EXPASS,{key}" + command = f"EXPASS,{key},,,{keystat}" return self.run(command, **kwargs) def gauge(self, opt="", freq="", **kwargs): From 43e1372b61bc58582af06bb5dcb87e79f6beaaef Mon Sep 17 00:00:00 2001 From: German Date: Wed, 18 Oct 2023 18:36:59 +0200 Subject: [PATCH 10/70] Removing prep7 after /verify --- src/ansys/mapdl/core/convert.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index e3ad0fe62f..b3f708c42d 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -721,7 +721,6 @@ def translate_line(self, line): if cmd_caps == "/VERIFY": self.store_run_command("FINISH") self.store_run_command(line) - self.store_command("prep7", "") return if cmd_caps_short == "*REP": From 7282a4487ca72cb269ee4f9420890d3c937ccf16 Mon Sep 17 00:00:00 2001 From: German Date: Wed, 18 Oct 2023 18:58:37 +0200 Subject: [PATCH 11/70] reducing white space in bypassed commands Getting ready for empty-commands. --- src/ansys/mapdl/core/convert.py | 97 +++++++++++++++++---------------- 1 file changed, 49 insertions(+), 48 deletions(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index b3f708c42d..1067d3d6d6 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -16,53 +16,54 @@ } # This commands have "--" as one or some arguments -COMMANDS_WITH_EMPTY_ARGS = [ - "/CMA", # "/CMAP, - "/NER", # "/NERR, - "/PBF", # "/PBF, - "/PMO", # "/PMORE, - "ANTY", # ANTYPE, - "ASBL", # ASBL, - "ATAN", # ATAN, - "BCSO", # BCSOPTION, - "CLOG", # CLOG, - "CONJ", # CONJUG, - "DERI", # DERIV, - "DSPO", # DSPOPTION, - "ENER", # ENERSOL, - "ENSY", # ENSYM, - "ESYM", # ESYM, - "EXP", # EXP, - "EXPA", # EXPAND, - "FCLI", # FCLIST, - "FILE", # FILEAUX2, - "FLUR", # FLUREAD, - "GMAT", # GMATRIX, - "IMAG", # IMAGIN, - "INT1", # INT1, - "LARG", # LARGE, - "LATT", # LATT, - "MAP", # MAP, - "MORP", # MORPH, - "MPCO", # MPCOPY, - "NLOG", # NLOG, - "PLMA", # PLMAP, - "PRED", # PRED, - "PROD", # PROD, - "QRDO", # QRDOPT, - "QUOT", # QUOT, - "RACE", # RACE, - "REAL", # REALVAR, - "REME", # REMESH, - "SESY", # SESYMM, - "SETF", # SETFGAP, - "SETR", # SETRAN, - "SMAL", # SMALL, - "SNOP", # SNOPTION, - "SURE", # SURESU, - "THOP", # THOPT, - "TINT", # TINTP, -] +COMMANDS_WITH_EMPTY_ARGS = { + "/CMA": (), # "/CMAP, + "/NER": (), # "/NERR, + "/PBF": (), # "/PBF, + "/PMO": (), # "/PMORE, + "ANTY": (), # ANTYPE, + "ASBL": (), # ASBL, + "ATAN": (), # ATAN, + "BCSO": (), # BCSOPTION, + "CLOG": (), # CLOG, + "CONJ": (), # CONJUG, + "DERI": (), # DERIV, + "DSPO": (), # DSPOPTION, + "ENER": (), # ENERSOL, + "ENSY": (), # ENSYM, + "ESYM": (), # ESYM, + "EXP": (), # EXP, + "EXPA": (), # EXPAND, + "FCLI": (), # FCLIST, + "FILE": (), # FILEAUX2, + "FLUR": (), # FLUREAD, + "GMAT": (), # GMATRIX, + "IMAG": (), # IMAGIN, + "INT1": (), # INT1, + "LARG": (), # LARGE, + "LATT": (), # LATT, + "MAP": (), # MAP, + "MORP": (), # MORPH, + "MPCO": (), # MPCOPY, + "NLOG": (), # NLOG, + "PLMA": (), # PLMAP, + "PRED": (), # PRED, + "PROD": (), # PROD, + "QRDO": (), # QRDOPT, + "QUOT": (), # QUOT, + "RACE": (), # RACE, + "REAL": (), # REALVAR, + "REME": (), # REMESH, + "SESY": (), # SESYMM, + "SETF": (), # SETFGAP, + "SETR": (), # SETRAN, + "SMAL": (), # SMALL, + "SNOP": (), # SNOPTION, + "SQRT": (), # SQRT + "SURE": (), # SURESU, + "THOP": (), # THOPT, + "TINT": (), # TINTP, +} COMMANDS_TO_NOT_BE_CONVERTED = [ @@ -742,7 +743,7 @@ def translate_line(self, line): cmd_caps_short in COMMANDS_WITH_EMPTY_ARGS and ",," in line_with_trailing_commas ): - self.store_run_command(line) + self.store_run_command(line.strip()) return # Skipping commands to not be converted From 773a43e0a56cc4cb0ab36fefaa9dc09f38525003 Mon Sep 17 00:00:00 2001 From: German Date: Wed, 18 Oct 2023 19:18:02 +0200 Subject: [PATCH 12/70] reducing white spacing Avoiding converting mode for the moment. --- src/ansys/mapdl/core/convert.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index 1067d3d6d6..195fe24a0e 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -67,7 +67,8 @@ COMMANDS_TO_NOT_BE_CONVERTED = [ - "CMPL" # CMPLOT default behaviour does not match the `mapdl.cmplot`'s at the moemnt + "CMPL", # CMPLOT default behaviour does not match the `mapdl.cmplot`'s at the moemnt + "MODE", # Until we merge #2431 ] @@ -672,7 +673,7 @@ def translate_line(self, line): cmd_caps = line.split(",")[0].upper() cmd_caps_short = cmd_caps[:4] - items = self._get_items(line) + items = self._get_items(line.strip()) if cmd_caps_short in ["SOLV", "LSSO"] and self._comment_solve: self.store_command( @@ -748,7 +749,7 @@ def translate_line(self, line): # Skipping commands to not be converted if cmd_caps_short in COMMANDS_TO_NOT_BE_CONVERTED: - self.store_run_command(line) + self.store_run_command(line.strip()) return if cmd_caps_short == "/TIT": # /TITLE @@ -873,9 +874,9 @@ def translate_line(self, line): self.start_non_interactive() if self._in_block and cmd_caps_short not in self._non_interactive_commands: - self.store_run_command(original_line) + self.store_run_command(original_line.strip()) else: - self.store_run_command(line) + self.store_run_command(line.strip()) elif self.use_function_names: if command[0] == "/": @@ -893,7 +894,7 @@ def translate_line(self, line): self.store_command(command, parameters) else: - self.store_run_command(line) + self.store_run_command(line.strip()) def _pymapdl_command(self, command): if command[0] in ["/", "*"]: From a82776886feac990bb5ed5db88c12721d9b66670 Mon Sep 17 00:00:00 2001 From: German Date: Wed, 18 Oct 2023 19:18:27 +0200 Subject: [PATCH 13/70] Adding arguments to ddoption --- .../_commands/solution/analysis_options.py | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/ansys/mapdl/core/_commands/solution/analysis_options.py b/src/ansys/mapdl/core/_commands/solution/analysis_options.py index effa873087..deed5ba9e5 100644 --- a/src/ansys/mapdl/core/_commands/solution/analysis_options.py +++ b/src/ansys/mapdl/core/_commands/solution/analysis_options.py @@ -1105,25 +1105,27 @@ def cutcontrol(self, lab="", value="", option="", **kwargs): command = f"CUTCONTROL,{lab},{value},{option}" return self.run(command, **kwargs) - def ddoption(self, decomp="", **kwargs): + def ddoption(self, decomp="", nprocpersol="", numsolforlp="", **kwargs): """Sets domain decomposer option for Distributed ANSYS. APDL Command: DDOPTION Parameters ---------- - decomp + Decomp Controls which domain decomposition algorithm to use. - AUTO - Use the default domain decomposition algorithm when splitting the model into - domains for Distributed ANSYS (default). + * AUTO - Automatically selects the optimal domain decomposition method (default). + * MESH - Decompose the FEA mesh. + * FREQ - Decompose the frequency domain for harmonic analyses. + * CYCHI -Decompose the harmonic indices for cyclic symmetry modal analyses. - GREEDY - Use the "greedy" domain decomposition algorithm. + nprocpersol + Number of processes to be used for mesh-based decomposition in conjunction with each frequency solution (`Decomp = FREQ`) or harmonic index solution (`Decomp = CYCHI`). Defaults to 1. This field + is ignored when `Decomp = MESH`. - METIS - Use the METIS graph partitioning domain decomposition algorithm. + numsolforlp + Number of frequency or harmonic index solutions in a subsequent linear perturbation harmonic or linear perturbation cyclic modal analysis. This field is ignored when `Decomp = MESH` Notes ----- From 08608693edfe9a939e3f2595b2e669ba18c8b6a0 Mon Sep 17 00:00:00 2001 From: German Date: Wed, 18 Oct 2023 20:02:59 +0200 Subject: [PATCH 14/70] Fixing vm double argument --- src/ansys/mapdl/core/examples/verif/vm132.dat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/examples/verif/vm132.dat b/src/ansys/mapdl/core/examples/verif/vm132.dat index 85cc37dbcb..98c7483d6c 100755 --- a/src/ansys/mapdl/core/examples/verif/vm132.dat +++ b/src/ansys/mapdl/core/examples/verif/vm132.dat @@ -22,7 +22,7 @@ D,ALL,ALL ! FIX ALL DOFS FINISH /SOLU NSUBST,100,100,100 -RATE,ON,ON +RATE,ON OUTPR,BASIC,10 ! PRINT BASIC SOLUTION FOR EVERY 10TH SUBSTEP OUTRES,ESOL,1 ! STORE ELEMENT SOLUTION FOR EVERY SUBSTEP /OUT,SCRATCH From d1c60993fb218f45628695a8d57c3b9788ea42be Mon Sep 17 00:00:00 2001 From: German Date: Wed, 18 Oct 2023 20:10:40 +0200 Subject: [PATCH 15/70] Fixing vm extra argument --- src/ansys/mapdl/core/examples/verif/vm139.dat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/examples/verif/vm139.dat b/src/ansys/mapdl/core/examples/verif/vm139.dat index 863ef1c87c..a71897ee7a 100755 --- a/src/ansys/mapdl/core/examples/verif/vm139.dat +++ b/src/ansys/mapdl/core/examples/verif/vm139.dat @@ -25,7 +25,7 @@ D,1,UX,,,,,UY,UZ D,11,UX,,,,,UZ D,ALL,ROTZ NSEL,S,LOC,X,22.5 -DSYM,SYMM,X,0,22.5 ! SYMMETRY B.C.'S AT CENTERLINE +DSYM,SYMM,X,0 ! SYMMETRY B.C.'S AT CENTERLINE NSEL,ALL FINISH /SOLU From 76b69fadc0cec65ef7c8bd415898851fed2c766a Mon Sep 17 00:00:00 2001 From: German Date: Wed, 18 Oct 2023 20:22:42 +0200 Subject: [PATCH 16/70] Fixing vm extra argument --- src/ansys/mapdl/core/examples/verif/vm139.dat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/examples/verif/vm139.dat b/src/ansys/mapdl/core/examples/verif/vm139.dat index a71897ee7a..cf126a7f0b 100755 --- a/src/ansys/mapdl/core/examples/verif/vm139.dat +++ b/src/ansys/mapdl/core/examples/verif/vm139.dat @@ -100,7 +100,7 @@ NSEL,R,LOC,Y,0 D,ALL,UY ALLSEL,ALL NSEL,S,LOC,X,22.5 -DSYM,SYMM,X,0,22.5 ! SYMMETRY B.C.'S AT CENTERLINE +DSYM,SYMM,X,0 ! SYMMETRY B.C.'S AT CENTERLINE NSEL,ALL FINISH /SOLU From 681005d0c059eb2f982ac83fee69599c854ec172 Mon Sep 17 00:00:00 2001 From: German Date: Wed, 18 Oct 2023 21:12:37 +0200 Subject: [PATCH 17/70] Fix double arg --- src/ansys/mapdl/core/examples/verif/vm147.dat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/examples/verif/vm147.dat b/src/ansys/mapdl/core/examples/verif/vm147.dat index 0b34f0f978..29676c2de1 100755 --- a/src/ansys/mapdl/core/examples/verif/vm147.dat +++ b/src/ansys/mapdl/core/examples/verif/vm147.dat @@ -26,7 +26,7 @@ VTYPE,1 ! NON-HIDDEN (FAST) METHOD GEOM,1,50 ! 2-D AXISYMMETRIC GEOM WITH 50 FACETS MPRINT,1 STEF,5.6696E-8 ! STEFAN-BOLTZMANN CONSTANT IN MKS UNITS -WRITE,CONE,SUB ! WRITE RADIATION SUBSTRUCTURE MATRIX +WRITE,CONE ! WRITE RADIATION SUBSTRUCTURE MATRIX FINISH /CLEAR,NOSTART ! CLEAR DATABASE; DO NOT READ START.ANS FILE /PREP7 From 129afc1d3b64ae8ba28dacdf4e3210be555b07f3 Mon Sep 17 00:00:00 2001 From: German Date: Wed, 18 Oct 2023 21:13:08 +0200 Subject: [PATCH 18/70] Fixing launcher reference --- doc/source/user_guide/launcher.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/user_guide/launcher.rst b/doc/source/user_guide/launcher.rst index d7b2028a79..cfc3c61941 100644 --- a/doc/source/user_guide/launcher.rst +++ b/doc/source/user_guide/launcher.rst @@ -6,7 +6,7 @@ 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: +the :func:`launch_mapdl() ` function: .. code:: python @@ -81,4 +81,4 @@ keyword argument: API reference ~~~~~~~~~~~~~ For more information on controlling how MAPDL launches locally, see the -description of the :func:`launch_mapdl() ` function. +description of the :func:`launch_mapdl() ` function. From 095a92cd7b204f7b8770c0c8cf1dbbb2d35aba88 Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 12:24:01 +0200 Subject: [PATCH 19/70] Fixing wrong parameter name in parres --- .../core/_commands/apdl/parameter_definition.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py b/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py index f459e70486..0236c0942f 100644 --- a/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py +++ b/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py @@ -518,13 +518,16 @@ def parres(self, lab="", fname="", ext="", **kwargs): >>> mapdl.parres('parm.PARM') """ - if ext: - fname = fname + "." + ext - elif not fname: - fname = "." + "PARM" + if not fname: + fname = self.jobname - if "Grpc" in self.__class__.__name__: # grpc mode - if self._local: + if not ext: + ext = "parm" # Although documentation says `PARM` + + fname = fname + "." + ext + + if self._mode == "grpc": # grpc mode + if self.is_local: # It must be a file! if os.path.isfile(fname): # And it exist! From ed584d416d01f502a09a7fdf5e1f2259c60b9abc Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 12:24:33 +0200 Subject: [PATCH 20/70] Exiting interactive (P) xsel function if in non_interactive. --- src/ansys/mapdl/core/mapdl.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ansys/mapdl/core/mapdl.py b/src/ansys/mapdl/core/mapdl.py index e6b310f312..ca9278bae0 100644 --- a/src/ansys/mapdl/core/mapdl.py +++ b/src/ansys/mapdl/core/mapdl.py @@ -475,6 +475,10 @@ def wrap_xsel_function_output(method): @wraps(func) def inner_wrapper(*args, **kwargs): # in interactive mode (item='p'), the output is not suppressed + if self._store_commands: + # In non-interactive mode, we do not need to check anything. + return + is_interactive_arg = ( True if len(args) >= 2 From 62cd7e323436387b7e2f500240c0ea7794d4eec1 Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 12:25:18 +0200 Subject: [PATCH 21/70] Avoiding parsing some unexisting commands. Avoiding consider 'INF' as infinitive (float). --- src/ansys/mapdl/core/convert.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index 195fe24a0e..727de6c570 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -69,6 +69,8 @@ COMMANDS_TO_NOT_BE_CONVERTED = [ "CMPL", # CMPLOT default behaviour does not match the `mapdl.cmplot`'s at the moemnt "MODE", # Until we merge #2431 + "/LIN", # Until we merge 2432 + "/LAR", # Until we merge 2432 ] @@ -989,7 +991,7 @@ def store_command(self, function, parameters): parsed_parameters = [] for parameter in parameters: parameter = parameter.strip() - if is_float(parameter): + if is_float(parameter) and parameter.upper() != "INF": parsed_parameters.append(parameter) elif "ARG" in parameter and self._infunction: parsed_parameters.append("%s" % parameter) From ef7a6747698021a0bdd3e9933e9653b87b68f358 Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 12:58:21 +0200 Subject: [PATCH 22/70] exiting early if in non_interactive when checking file path. --- src/ansys/mapdl/core/mapdl_grpc.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ansys/mapdl/core/mapdl_grpc.py b/src/ansys/mapdl/core/mapdl_grpc.py index dce09f08b2..2542f97711 100644 --- a/src/ansys/mapdl/core/mapdl_grpc.py +++ b/src/ansys/mapdl/core/mapdl_grpc.py @@ -1871,6 +1871,10 @@ def _get_file_path(self, fname: str, progress_bar: bool = False) -> str: overwriting the MAPDL directory copy. """ + if self._store_commands: + # Exiting early if in non-interactive mode. + return fname + if os.path.isdir(fname): raise ValueError( f"`fname` should be a full file path or name, not the directory '{fname}'." From 5e9c5d2456961563f7f44f636eb31cca0bb6917e Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 13:07:48 +0200 Subject: [PATCH 23/70] adding check_parameter_names argument to converter and mapdl Add other arguments to cli Avoiding `/type` conversion Passing MAPDL arguments from launcher_mapdl to MAPDL class --- src/ansys/mapdl/core/convert.py | 53 ++++++++++++++++++++++++++++++-- src/ansys/mapdl/core/launcher.py | 26 +++++++++++----- src/ansys/mapdl/core/mapdl.py | 8 ++++- tests/test_convert.py | 16 ++++++++++ tests/test_mapdl.py | 9 ++++++ 5 files changed, 101 insertions(+), 11 deletions(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index 727de6c570..8f20a9a532 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -71,6 +71,7 @@ "MODE", # Until we merge #2431 "/LIN", # Until we merge 2432 "/LAR", # Until we merge 2432 + "/TYP", # Until we merge 2432 ] @@ -92,6 +93,7 @@ def convert_script( only_commands=False, use_vtk=None, clear_at_start=False, + check_parameter_names=True, ): """Converts an ANSYS input file to a python PyMAPDL script. @@ -227,6 +229,7 @@ def convert_script( only_commands=only_commands, use_vtk=use_vtk, clear_at_start=clear_at_start, + check_parameter_names=check_parameter_names, ) translator.save(filename_out) @@ -250,6 +253,7 @@ def convert_apdl_block( only_commands=False, use_vtk=None, clear_at_start=False, + check_parameter_names=False, ): """Converts an ANSYS input string to a python PyMAPDL string. @@ -319,10 +323,14 @@ def convert_apdl_block( use_vtk : bool, optional It sets the `mapdl.use_vtk` argument equals True or False depending on - this value. + this value. Defaults to `None` which is Mapdl class default. clear_at_start : bool, optional - Add a `mapdl.clear()` after the Mapdl object initialization. + Add a `mapdl.clear()` after the Mapdl object initialization. Defaults to + `False`. + + check_parameter_names : bool, optional + Set MAPDL object to avoid parameter name checks (do not raise leading underscored parameter exceptions). Defaults to `False`. Returns ------- @@ -362,6 +370,7 @@ def convert_apdl_block( only_commands=only_commands, use_vtk=use_vtk, clear_at_start=clear_at_start, + check_parameter_names=check_parameter_names, ) if isinstance(apdl_strings, str): @@ -386,6 +395,7 @@ def _convert( only_commands=False, use_vtk=None, clear_at_start=False, + check_parameter_names=True, ): if only_commands: auto_exit = False @@ -406,6 +416,7 @@ def _convert( print_com=print_com, use_vtk=use_vtk, clear_at_start=clear_at_start, + check_parameter_names=check_parameter_names, ) if isinstance(apdl_strings, str): @@ -470,6 +481,7 @@ def __init__( print_com=True, use_vtk=None, clear_at_start=False, + check_parameter_names=False, ): self._non_interactive_level = 0 self.lines = Lines(mute=not show_log) @@ -490,6 +502,7 @@ def __init__( self.verification_example = False self.use_vtk = use_vtk self.clear_at_start = clear_at_start + self.check_parameter_names = check_parameter_names self.macros_names = [] self.write_header() @@ -601,6 +614,9 @@ def initialize_mapdl_object(self, loglevel, exec_file): if self.use_vtk is not None: mapdl_arguments.append(f"use_vtk={bool(self.use_vtk)}") + if self.check_parameter_names is not None and not self.check_parameter_names: + mapdl_arguments.append(f"check_parameter_names=False") + line = f'{self.obj_name} = launch_mapdl({", ".join(mapdl_arguments)})' self.lines.append(line) @@ -1165,6 +1181,31 @@ def _get_items(self, line_): default=True, help="Print command ``/COM`` arguments to python console. Defaults to ``True``.", ) +@click.option( + "--only_commands", + default=False, + help="""converts only the commands, meaning that header + (``header=False``), imports (``add_imports=False``), + and exit commands are NOT included (``auto_exit=False``). + Overrides ``header``, ``add_imports`` and ``auto_exit``.""", +) +@click.option( + "--use_vtk", + default=None, + help="""It sets the `mapdl.use_vtk` argument equals True or False depending on + this value.""", +) +@click.option( + "--clear_at_start", + default=False, + help="""Add a `mapdl.clear()` after the Mapdl object initialization. Defaults to + `False`.""", +) +@click.option( + "--check_parameter_names", + default=False, + help="""Set MAPDL object to avoid parameter name checks (do not raise leading underscored parameter exceptions). Defaults to `False`.""", +) def cli( filename_in, o, @@ -1181,6 +1222,10 @@ def cli( cleanup_output, header, print_com, + only_commands, + use_vtk, + clear_at_start, + check_parameter_names, ): """PyMAPDL CLI tool for converting MAPDL scripts to PyMAPDL scripts. @@ -1228,6 +1273,10 @@ def cli( cleanup_output, header, print_com, + only_commands, + use_vtk, + clear_at_start, + check_parameter_names, ) if filename_out: diff --git a/src/ansys/mapdl/core/launcher.py b/src/ansys/mapdl/core/launcher.py index a50a4758d9..987789647a 100644 --- a/src/ansys/mapdl/core/launcher.py +++ b/src/ansys/mapdl/core/launcher.py @@ -32,6 +32,7 @@ VersionError, ) from ansys.mapdl.core.licensing import ALLOWABLE_LICENSES, LicenseChecker +from ansys.mapdl.core.mapdl import _ALLOWED_START_PARM from ansys.mapdl.core.mapdl_grpc import MAX_MESSAGE_LENGTH, MapdlGrpc from ansys.mapdl.core.misc import ( check_valid_ip, @@ -1356,6 +1357,13 @@ def launch_mapdl( force_intel = kwargs.pop("force_intel", False) broadcast = kwargs.pop("log_broadcast", False) + # Transferring MAPDL arguments to start_parameters: + start_parm = {} + + for each_par in kwargs: + if each_par in _ALLOWED_START_PARM: + start_parm[each_par] = kwargs.pop(each_par) + # Raising error if using non-allowed arguments if kwargs: ms_ = ", ".join([f"'{each}'" for each in kwargs.keys()]) @@ -1556,14 +1564,16 @@ def launch_mapdl( additional_switches = _check_license_argument(license_type, additional_switches) LOG.debug(f"Using additional switches {additional_switches}.") - start_parm = { - "exec_file": exec_file, - "run_location": run_location, - "additional_switches": additional_switches, - "jobname": jobname, - "nproc": nproc, - "print_com": print_com, - } + start_parm.update( + { + "exec_file": exec_file, + "run_location": run_location, + "additional_switches": additional_switches, + "jobname": jobname, + "nproc": nproc, + "print_com": print_com, + } + ) if mode in ["console", "corba"]: start_parm["start_timeout"] = start_timeout diff --git a/src/ansys/mapdl/core/mapdl.py b/src/ansys/mapdl/core/mapdl.py index ca9278bae0..a0f79fe7e0 100644 --- a/src/ansys/mapdl/core/mapdl.py +++ b/src/ansys/mapdl/core/mapdl.py @@ -193,7 +193,9 @@ def setup_logger(loglevel="INFO", log_file=True, mapdl_instance=None): "process", "ram", "run_location", - "start_timeout" "timeout", + "start_timeout", + "timeout", + "check_parameter_names", ] @@ -267,6 +269,7 @@ def __init__( self._jobname: str = start_parm.get("jobname", "file") self._path: Union[str, pathlib.Path] = start_parm.get("run_location", None) self._print_com: bool = print_com # print the command /COM input. + self.check_parameter_names = start_parm.get("check_parameter_names", True) # Setting up loggers self._log: logging.Logger = logger.add_instance_logger( @@ -3983,6 +3986,9 @@ def get_nodal_constrains(self, label=None): def _check_parameter_name(self, param_name): """Checks if a parameter name is allowed or not.""" + if not self.check_parameter_names: + return + param_name = param_name.strip() match_valid_parameter_name = r"^[a-zA-Z_][a-zA-Z\d_\(\),\s\%]{0,31}$" diff --git a/tests/test_convert.py b/tests/test_convert.py index a4e5aa6306..73a0fc84bd 100644 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -477,6 +477,22 @@ def test_use_vtk(vtk): assert f"use_vtk={vtk}" in output +@pytest.mark.parametrize("check_parameter_names", [None, True, False]) +def test_check_parameter_names(check_parameter_names): + output = convert_apdl_block( + "/view,1,1,1", + only_commands=False, + add_imports=True, + check_parameter_names=check_parameter_names, + ) + assert "mapdl.view(1, 1, 1)" in output + assert "launch_mapdl" in output + if check_parameter_names is not None and not check_parameter_names: + assert "check_parameter_names=False" in output + else: + assert f"check_parameter_names" not in output + + @pytest.mark.parametrize("clear_at_start", [None, True, False]) def test_clear_at_start(clear_at_start): output = convert_apdl_block( diff --git a/tests/test_mapdl.py b/tests/test_mapdl.py index 063b878162..0bc5b79eaf 100644 --- a/tests/test_mapdl.py +++ b/tests/test_mapdl.py @@ -1995,3 +1995,12 @@ def test_non_valid_kwarg(mapdl): with pytest.warns(UserWarning): mapdl.cdwrite(options="DB", fname="test1", ext="cdb") + + +def test_check_parameter_names(mapdl): + with pytest.raises(ValueError): + mapdl.parameters["_dummy"] = 1 + + mapdl.check_parameter_names = False + mapdl.parameters["_dummy"] = 1 + mapdl.check_parameter_names = True # returning to default From 06294ab0a5204b6875ffd921fbd496cea9422f3d Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 13:08:05 +0200 Subject: [PATCH 24/70] Removing extra /out in vm51 --- src/ansys/mapdl/core/examples/verif/vm51.dat | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ansys/mapdl/core/examples/verif/vm51.dat b/src/ansys/mapdl/core/examples/verif/vm51.dat index cc02967b5e..69cbeafcaa 100755 --- a/src/ansys/mapdl/core/examples/verif/vm51.dat +++ b/src/ansys/mapdl/core/examples/verif/vm51.dat @@ -1,5 +1,4 @@ /COM,ANSYS MEDIA REL. 2023R2 (05/12/2023) REF. VERIF. MANUAL: REL. 2023R2 -/OUT,SCRATCH /VERIFY,VM51 JPGPRF,500,100,1 ! MACRO TO SET PREFS FOR JPEG PLOTS /SHOW,JPEG From ed5b1a66280edfa05230b49113a7b36000dd9939 Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 13:18:01 +0200 Subject: [PATCH 25/70] Avoiding dict changing size and passing start arguments to cases where we are connecting to already existing instances. --- src/ansys/mapdl/core/launcher.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/launcher.py b/src/ansys/mapdl/core/launcher.py index 987789647a..d83a41a160 100644 --- a/src/ansys/mapdl/core/launcher.py +++ b/src/ansys/mapdl/core/launcher.py @@ -1360,7 +1360,8 @@ def launch_mapdl( # Transferring MAPDL arguments to start_parameters: start_parm = {} - for each_par in kwargs: + kwargs_keys = list(kwargs.keys()) + for each_par in kwargs_keys: if each_par in _ALLOWED_START_PARM: start_parm[each_par] = kwargs.pop(each_par) @@ -1457,6 +1458,7 @@ def launch_mapdl( cleanup_on_exit=False, loglevel=loglevel, set_no_abort=set_no_abort, + **start_parm, ) GALLERY_INSTANCE[0] = {"ip": mapdl._ip, "port": mapdl._port} return mapdl @@ -1469,6 +1471,7 @@ def launch_mapdl( cleanup_on_exit=False, loglevel=loglevel, set_no_abort=set_no_abort, + **start_parm, ) if clear_on_connect: mapdl.clear() @@ -1482,6 +1485,7 @@ def launch_mapdl( cleanup_on_exit=False, loglevel=loglevel, set_no_abort=set_no_abort, + **start_parm, ) if clear_on_connect: mapdl.clear() @@ -1497,6 +1501,7 @@ def launch_mapdl( loglevel=loglevel, set_no_abort=set_no_abort, log_apdl=log_apdl, + **start_parm, ) if clear_on_connect: mapdl.clear() From 229900cc13ca4c08c471b97a6694d9d5e9d3503f Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 14:18:21 +0200 Subject: [PATCH 26/70] Better parsing CLI arguments. Adding `ADD` to skipped arguments --- src/ansys/mapdl/core/convert.py | 90 ++++++++++++++++++++++++++------- 1 file changed, 73 insertions(+), 17 deletions(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index 8f20a9a532..5e187aabf4 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -15,12 +15,31 @@ "max-line-length": 100, } +LOGLEVEL_DEFAULT = "WARNING" +AUTO_EXIT_DEFAULT = True +LINE_ENDING_DEFAULT = None +EXEC_FILE_DEFAULT = None +MACROS_AS_FUNCTIONS_DEFAULT = True +USE_FUNCTION_NAMES_DEFAULT = True +SHOW_LOG_DEFAULT = False +ADD_IMPORTS_DEFAULT = True +COMMENT_SOLVE_DEFAULT = False +CLEANUP_OUTPUT_DEFAULT = True +HEADER_DEFAULT = True +PRINT_COM_DEFAULT = PRINT_COM_DEFAULT +ONLY_COMMANDS_DEFAULT = False +USE_VTK_DEFAULT = None +CLEAR_AT_START_DEFAULT = False +CHECK_PARAMETER_NAMES_DEFAULT = True + + # This commands have "--" as one or some arguments COMMANDS_WITH_EMPTY_ARGS = { "/CMA": (), # "/CMAP, "/NER": (), # "/NERR, "/PBF": (), # "/PBF, "/PMO": (), # "/PMORE, + "ADD": (), # "ADD" "ANTY": (), # ANTYPE, "ASBL": (), # ASBL, "ATAN": (), # ATAN, @@ -1127,63 +1146,67 @@ def _get_items(self, line_): @click.option("--filename_out", default=None, help="Name of the output Python script.") @click.option( "--loglevel", - default="WARNING", + default=LOGLEVEL_DEFAULT, help="Logging level of the ansys object within the script.", ) @click.option( "--auto_exit", - default=True, + default=AUTO_EXIT_DEFAULT, help="Adds a line to the end of the script to exit MAPDL. Default ``True``", ) -@click.option("--line_ending", default=None, help="When None, automatically is ``\n.``") +@click.option( + "--line_ending", + default=LINE_ENDING_DEFAULT, + help="When None, automatically is ``\n.``", +) @click.option( "--exec_file", - default=None, + default=EXEC_FILE_DEFAULT, help="Specify the location of the ANSYS executable and include it in the converter output ``launch_mapdl`` call.", ) @click.option( "--macros_as_functions", - default=True, + default=MACROS_AS_FUNCTIONS_DEFAULT, help="Attempt to convert MAPDL macros to python functions.", ) @click.option( "--use_function_names", - default=True, + default=USE_FUNCTION_NAMES_DEFAULT, help="Convert MAPDL functions to ansys.mapdl.core.Mapdl class methods. When ``True``, the MAPDL command ``K`` will be converted to ``mapdl.k``. When ``False``, it will be converted to ``mapdl.run('k')``.", ) @click.option( "--show_log", - default=False, + default=SHOW_LOG_DEFAULT, help="Print the converted commands using a logger (from ``logging`` Python module).", ) @click.option( "--add_imports", - default=True, + default=ADD_IMPORTS_DEFAULT, help='If ``True``, add the lines ``from ansys.mapdl.core import launch_mapdl`` and ``mapdl = launch_mapdl(loglevel="WARNING")`` to the beginning of the output file. This option is useful if you are planning to use the output script from another mapdl session. See examples section. This option overrides ``auto_exit``.', ) @click.option( "--comment_solve", - default=False, + default=COMMENT_SOLVE_DEFAULT, help='If ``True``, it will pythonically comment the lines that contain ``"SOLVE"`` or ``"/EOF"``.', ) @click.option( "--cleanup_output", - default=True, + default=CLEANUP_OUTPUT_DEFAULT, help="If ``True`` the output is formatted using ``autopep8`` before writing the file or returning the string. This requires ``autopep8`` to be installed.", ) @click.option( "--header", - default=True, + default=HEADER_DEFAULT, help="If ``True``, the default header is written in the first line of the output. If a string is provided, this string will be used as header.", ) @click.option( "--print_com", - default=True, + default=PRINT_COM_DEFAULT, help="Print command ``/COM`` arguments to python console. Defaults to ``True``.", ) @click.option( "--only_commands", - default=False, + default=ONLY_COMMANDS_DEFAULT, help="""converts only the commands, meaning that header (``header=False``), imports (``add_imports=False``), and exit commands are NOT included (``auto_exit=False``). @@ -1191,20 +1214,20 @@ def _get_items(self, line_): ) @click.option( "--use_vtk", - default=None, + default=USE_VTK_DEFAULT, help="""It sets the `mapdl.use_vtk` argument equals True or False depending on this value.""", ) @click.option( "--clear_at_start", - default=False, + default=CLEAR_AT_START_DEFAULT, help="""Add a `mapdl.clear()` after the Mapdl object initialization. Defaults to `False`.""", ) @click.option( "--check_parameter_names", - default=False, - help="""Set MAPDL object to avoid parameter name checks (do not raise leading underscored parameter exceptions). Defaults to `False`.""", + default=CHECK_PARAMETER_NAMES_DEFAULT, + help="""Set MAPDL object to avoid parameter name checks (do not raise leading underscored parameter exceptions). Defaults to `True`.""", ) def cli( filename_in, @@ -1258,6 +1281,30 @@ def cli( if o: filename_out = o + # Parsing commands: + loglevel = _parse_cli_command(loglevel, LOGLEVEL_DEFAULT) + auto_exit = _parse_cli_command(auto_exit, AUTO_EXIT_DEFAULT) + line_ending = _parse_cli_command(line_ending, LINE_ENDING_DEFAULT) + exec_file = _parse_cli_command(exec_file, EXEC_FILE_DEFAULT) + macros_as_functions = _parse_cli_command( + macros_as_functions, MACROS_AS_FUNCTIONS_DEFAULT + ) + use_function_names = _parse_cli_command( + use_function_names, USE_FUNCTION_NAMES_DEFAULT + ) + show_log = _parse_cli_command(show_log, SHOW_LOG_DEFAULT) + add_imports = _parse_cli_command(add_imports, ADD_IMPORTS_DEFAULT) + comment_solve = _parse_cli_command(comment_solve, COMMENT_SOLVE_DEFAULT) + cleanup_output = _parse_cli_command(cleanup_output, CLEANUP_OUTPUT_DEFAULT) + header = _parse_cli_command(header, HEADER_DEFAULT) + print_com = _parse_cli_command(print_com, PRINT_COM_DEFAULT) + only_commands = _parse_cli_command(only_commands, ONLY_COMMANDS_DEFAULT) + use_vtk = _parse_cli_command(use_vtk, USE_VTK_DEFAULT) + clear_at_start = _parse_cli_command(clear_at_start, CLEAR_AT_START_DEFAULT) + check_parameter_names = _parse_cli_command( + check_parameter_names, CHECK_PARAMETER_NAMES_DEFAULT + ) + convert_script( filename_in, filename_out, @@ -1285,3 +1332,12 @@ def cli( print( f"File {filename_in} successfully converted to {os.path.splitext(filename_in)[0] + '.py'}." ) + + +def _parse_cli_command(command, default=None): + if command.upper() == "TRUE": + return True + elif command.upper() == "FALSE": + return False + else: + return default From 1cf59be7e54ba8bbfba6af6eb59c4162f2d89eaa Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 14:18:51 +0200 Subject: [PATCH 27/70] Exiting early some functions when in `non_interactive` --- src/ansys/mapdl/core/mapdl.py | 8 ++------ src/ansys/mapdl/core/mapdl_grpc.py | 3 ++- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/ansys/mapdl/core/mapdl.py b/src/ansys/mapdl/core/mapdl.py index a0f79fe7e0..913655bd7f 100644 --- a/src/ansys/mapdl/core/mapdl.py +++ b/src/ansys/mapdl/core/mapdl.py @@ -2026,7 +2026,7 @@ def __enter__(self) -> None: "``vtk=True``" ) - if not self._parent()._png_mode: + if self._parent()._store_commands or not self._parent()._png_mode: self._parent().show("PNG", mute=True) self._parent().gfile(self._pixel_res, mute=True) @@ -2038,16 +2038,12 @@ def __enter__(self) -> None: def __exit__(self, *args) -> None: self._parent()._log.debug("Exiting in 'WithInterativePlotting' mode") self._parent().show("close", mute=True) - if not self._parent()._png_mode: + if self._parent()._store_commands or not self._parent()._png_mode: self._parent().show("PNG", mute=True) self._parent().gfile(self._pixel_res, mute=True) self._parent().file_type_for_plots = self.previous_device - def __exit__(self, *args) -> None: - self._parent()._log.debug("Exiting in 'WithInterativePlotting' mode") - self._parent().show("close", mute=True) - @property def _has_matplotlib(self): try: diff --git a/src/ansys/mapdl/core/mapdl_grpc.py b/src/ansys/mapdl/core/mapdl_grpc.py index 2542f97711..2804a8a558 100644 --- a/src/ansys/mapdl/core/mapdl_grpc.py +++ b/src/ansys/mapdl/core/mapdl_grpc.py @@ -3038,7 +3038,8 @@ def vget( ) -> NDArray[np.float64]: """Wraps VGET""" super().vget(par=par, ir=ir, tstrt=tstrt, kcplx=kcplx, **kwargs) - return self.parameters[par] + if not self._store_commands: + return self.parameters[par] def get_variable( self, From c0543608c790b2d012ffe799f88f198632aae73b Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 14:19:22 +0200 Subject: [PATCH 28/70] Making sure we are passing vtk --- src/ansys/mapdl/core/launcher.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/launcher.py b/src/ansys/mapdl/core/launcher.py index d83a41a160..f592a77e63 100644 --- a/src/ansys/mapdl/core/launcher.py +++ b/src/ansys/mapdl/core/launcher.py @@ -1356,6 +1356,7 @@ def launch_mapdl( # Extract arguments: force_intel = kwargs.pop("force_intel", False) broadcast = kwargs.pop("log_broadcast", False) + use_vtk = kwargs.pop("use_vtk", None) # Transferring MAPDL arguments to start_parameters: start_parm = {} @@ -1471,6 +1472,7 @@ def launch_mapdl( cleanup_on_exit=False, loglevel=loglevel, set_no_abort=set_no_abort, + use_vtk=use_vtk, **start_parm, ) if clear_on_connect: @@ -1485,6 +1487,7 @@ def launch_mapdl( cleanup_on_exit=False, loglevel=loglevel, set_no_abort=set_no_abort, + use_vtk=use_vtk, **start_parm, ) if clear_on_connect: @@ -1501,6 +1504,7 @@ def launch_mapdl( loglevel=loglevel, set_no_abort=set_no_abort, log_apdl=log_apdl, + use_vtk=use_vtk, **start_parm, ) if clear_on_connect: @@ -1600,7 +1604,9 @@ def launch_mapdl( if mode == "console": from ansys.mapdl.core.mapdl_console import MapdlConsole - mapdl = MapdlConsole(loglevel=loglevel, log_apdl=log_apdl, **start_parm) + mapdl = MapdlConsole( + loglevel=loglevel, log_apdl=log_apdl, use_vtk=use_vtk, **start_parm + ) elif mode == "corba": try: # pending deprecation to ansys-mapdl-corba @@ -1616,6 +1622,7 @@ def launch_mapdl( log_apdl=log_apdl, log_broadcast=broadcast, verbose=verbose_mapdl, + use_vtk=use_vtk, **start_parm, ) elif mode == "grpc": @@ -1636,6 +1643,7 @@ def launch_mapdl( remove_temp_dir_on_exit=remove_temp_dir_on_exit, log_apdl=log_apdl, process=process, + use_vtk=use_vtk, **start_parm, ) if run_location is None: From 2a9f4fd54b231cbd7ac9f082f753c39fd2d07140 Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 14:21:43 +0200 Subject: [PATCH 29/70] Better CLI parsing --- src/ansys/mapdl/core/convert.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index 5e187aabf4..ee04965940 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -26,7 +26,7 @@ COMMENT_SOLVE_DEFAULT = False CLEANUP_OUTPUT_DEFAULT = True HEADER_DEFAULT = True -PRINT_COM_DEFAULT = PRINT_COM_DEFAULT +PRINT_COM_DEFAULT = True ONLY_COMMANDS_DEFAULT = False USE_VTK_DEFAULT = None CLEAR_AT_START_DEFAULT = False @@ -1335,6 +1335,11 @@ def cli( def _parse_cli_command(command, default=None): + if isinstance(command, bool): + return command + if command is None: + return + if command.upper() == "TRUE": return True elif command.upper() == "FALSE": From a8ec466cb449706901b872ed461003cd3baf2823 Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 14:35:17 +0200 Subject: [PATCH 30/70] Avoiding some checks while in non_interactive. Cache Device at the beginning of the session. --- src/ansys/mapdl/core/mapdl.py | 31 ++++++++++++++++++++---------- src/ansys/mapdl/core/mapdl_grpc.py | 1 + 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/ansys/mapdl/core/mapdl.py b/src/ansys/mapdl/core/mapdl.py index 913655bd7f..11bb563ec5 100644 --- a/src/ansys/mapdl/core/mapdl.py +++ b/src/ansys/mapdl/core/mapdl.py @@ -369,6 +369,9 @@ def check_status(self): @property def file_type_for_plots(self): """Returns the current file type for plotting.""" + if not self._file_type_for_plots: + self._run("/show, PNG") + self._file_type_for_plots = "PNG" return self._file_type_for_plots @file_type_for_plots.setter @@ -2026,23 +2029,31 @@ def __enter__(self) -> None: "``vtk=True``" ) - if self._parent()._store_commands or not self._parent()._png_mode: - self._parent().show("PNG", mute=True) - self._parent().gfile(self._pixel_res, mute=True) + if not self._parent()._store_commands: + if not self._parent()._png_mode: + self._parent().show("PNG", mute=True) + self._parent().gfile(self._pixel_res, mute=True) - self.previous_device = self._parent().file_type_for_plots + self.previous_device = self._parent().file_type_for_plots - if self._parent().file_type_for_plots not in ["PNG", "TIFF", "PNG", "VRML"]: - self._parent().show(self._parent().default_file_type_for_plots) + if self._parent().file_type_for_plots not in [ + "PNG", + "TIFF", + "PNG", + "VRML", + ]: + self._parent().show(self._parent().default_file_type_for_plots) def __exit__(self, *args) -> None: self._parent()._log.debug("Exiting in 'WithInterativePlotting' mode") self._parent().show("close", mute=True) - if self._parent()._store_commands or not self._parent()._png_mode: - self._parent().show("PNG", mute=True) - self._parent().gfile(self._pixel_res, mute=True) - self._parent().file_type_for_plots = self.previous_device + if not self._parent()._store_commands: + if not self._parent()._png_mode: + self._parent().show("PNG", mute=True) + self._parent().gfile(self._pixel_res, mute=True) + + self._parent().file_type_for_plots = self.previous_device @property def _has_matplotlib(self): diff --git a/src/ansys/mapdl/core/mapdl_grpc.py b/src/ansys/mapdl/core/mapdl_grpc.py index 2804a8a558..e0a17efb0a 100644 --- a/src/ansys/mapdl/core/mapdl_grpc.py +++ b/src/ansys/mapdl/core/mapdl_grpc.py @@ -873,6 +873,7 @@ def _run_at_connect(self): self.show(self._file_type_for_plots) self.version # Caching version + self.file_type_for_plots # Setting /show,png and caching it. def _reset_cache(self): """Reset cached items.""" From 719832d36ef4776c2ed4e2f81a141a3488a4861b Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 14:44:27 +0200 Subject: [PATCH 31/70] Removing extra arguments in SUBOPT. --- src/ansys/mapdl/core/examples/verif/vm309.dat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/examples/verif/vm309.dat b/src/ansys/mapdl/core/examples/verif/vm309.dat index 0eae3c8044..ae5776c976 100644 --- a/src/ansys/mapdl/core/examples/verif/vm309.dat +++ b/src/ansys/mapdl/core/examples/verif/vm309.dat @@ -95,7 +95,7 @@ FINISH OUTRES,ALL,ALL ANTYPE,1 BUCOPT,LANB,3 -SUBOPT,0,0,0,0,0,ALL +SUBOPT,0,0 MXPAND,3,,,YES SOLVE FINISH From 408bd69407cf041086f5906186d760685cf1f5c8 Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 14:44:38 +0200 Subject: [PATCH 32/70] Adding more commands to ignores --- src/ansys/mapdl/core/convert.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index ee04965940..f0ada56aea 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -73,6 +73,8 @@ "RACE": (), # RACE, "REAL": (), # REALVAR, "REME": (), # REMESH, + "SECR": (), # SECREAD + "SECW": (), # SECWRITE "SESY": (), # SESYMM, "SETF": (), # SETFGAP, "SETR": (), # SETRAN, From 82c898d68bf92052241c7364127749bee1adf1b9 Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 14:52:54 +0200 Subject: [PATCH 33/70] Force output in png mode retrieval --- src/ansys/mapdl/core/mapdl.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ansys/mapdl/core/mapdl.py b/src/ansys/mapdl/core/mapdl.py index 11bb563ec5..a06cffba01 100644 --- a/src/ansys/mapdl/core/mapdl.py +++ b/src/ansys/mapdl/core/mapdl.py @@ -2067,7 +2067,8 @@ def _has_matplotlib(self): @property def _png_mode(self): """Returns True when MAPDL is set to write plots as png to file.""" - return "PNG" in self.show(mute=False) + with self.force_output: + return "PNG" in self.show(mute=False) def set_log_level(self, loglevel: DEBUG_LEVELS) -> None: """Sets log level @@ -3259,7 +3260,7 @@ def run( command = "/CLE,NOSTART" # Tracking output device - if command[:4].upper() == "/SHO": + if command[:4].upper() == "/SHO" and "," in command: self._file_type_for_plots = command.split(",")[1].upper() # Invalid commands silently ignored. From f7fc28c58af82f81f16aeff9fc7bc32468343c19 Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 14:57:55 +0200 Subject: [PATCH 34/70] adding missing argument to prcamp --- .../mapdl/core/_commands/post1_/special.py | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/ansys/mapdl/core/_commands/post1_/special.py b/src/ansys/mapdl/core/_commands/post1_/special.py index 74659aed3b..25e8831ea6 100644 --- a/src/ansys/mapdl/core/_commands/post1_/special.py +++ b/src/ansys/mapdl/core/_commands/post1_/special.py @@ -1748,6 +1748,7 @@ def prcamp( stabval="", keyallfreq="", keynegfreq="", + keywhirl="", **kwargs, ): """Prints Campbell diagram data for applications involving rotating @@ -1768,19 +1769,18 @@ def prcamp( slope The slope of the line to be printed. This value must be positive. - SLOPE > 0 - The line represents the number of excitations per revolution of the rotor. For - example, SLOPE = 1 represents one excitation per - revolution, usually resulting from unbalance. + SLOPE > 0 - The line represents the number of excitations per + revolution of the rotor. For example, SLOPE = 1 represents one + excitation per revolution, usually resulting from unbalance. - SLOPE = 0 - The line represents the stability threshold for stability values or logarithmic - decrements printout (STABVAL = 1 or 2) + SLOPE = 0 - The line represents the stability threshold for stability + values or logarithmic decrements printout (STABVAL = 1 or 2) unit Specifies the unit of measurement for rotational angular velocities: - RDS - Rotational angular velocities in radians per second (rad/s). This value is the - default. + RDS - Rotational angular velocities in radians per second (rad/s). This value is the default. RPM - Rotational angular velocities in revolutions per minute (RPMs). @@ -1794,8 +1794,8 @@ def prcamp( stabval Flag to print the stability values: - 0 (OFF or NO) - Print the frequencies (the imaginary parts of the eigenvalues in Hz). This - value is the default. + 0 (OFF or NO) - Print the frequencies (the imaginary parts of the + eigenvalues in Hz). This value is the default. 1 (ON or YES) - Print the stability values (the real parts of the eigenvalues in Hz). @@ -1804,9 +1804,8 @@ def prcamp( keyallfreq Key to specify if all frequencies above FREQB are printed out: - 0 (OFF or NO) - A maximum of 10 frequencies are printed out. They correspond to the frequencies - displayed via the PLCAMP command. This value is the - default. + 0 (OFF or NO) - A maximum of 10 frequencies are printed out. They + correspond to the frequencies displayed via the PLCAMP command. This value is the default. 1 (ON or YES) - All frequencies are printed out. @@ -1819,6 +1818,12 @@ def prcamp( 1 (ON or YES) - Negative and positive frequencies are printed out. + keywhirl + Flag to print the whirl and instability keys for each load step: + + 0 (OFF or NO) - Print the whirl for the last load step. This value is the default. + 1 (ON or YES) - Print the whirl and instability keys for each load step. + Notes ----- The following items are required when generating a Campbell diagram: From 79ce70bdc1d83701d251394134e21e9aa9f9dd25 Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 15:35:14 +0200 Subject: [PATCH 35/70] Avoiding parameter name issue when extension is part of name and not supplied independently. --- .../mapdl/core/_commands/apdl/parameter_definition.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py b/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py index 0236c0942f..3efa3fab43 100644 --- a/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py +++ b/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py @@ -521,10 +521,10 @@ def parres(self, lab="", fname="", ext="", **kwargs): if not fname: fname = self.jobname - if not ext: - ext = "parm" # Although documentation says `PARM` - - fname = fname + "." + ext + fname = self._get_file_name( + fname=fname, ext=ext, default_extension="parm" + ) # Although documentation says `PARM` + file_, ext_, _ = self._decompose_fname(fname) if self._mode == "grpc": # grpc mode if self.is_local: From a61af5e28f60c92decf1cc7c52aa392eb339e5fb Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 15:35:28 +0200 Subject: [PATCH 36/70] Updating converter golden tests --- tests/test_convert.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/test_convert.py b/tests/test_convert.py index 73a0fc84bd..631667bbcf 100644 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -39,34 +39,34 @@ pynblock = """with mapdl.non_interactive: mapdl.run("nblock,3,,326253") mapdl.run("(1i9,3e20.9e3)") - mapdl.run(" 1 3.352881632E-03 1.110639271E-02 5.172433282E-03") - mapdl.run(" 2 3.485685736E-03 1.110981270E-02 4.999255638E-03") - mapdl.run(" 3 3.615164748E-03 1.111323677E-02 4.823719994E-03") - mapdl.run(" 4 3.673859471E-03 1.111439119E-02 4.740300611E-03") - mapdl.run(" 5 3.709417144E-03 1.111407057E-02 4.691582629E-03") + mapdl.run("1 3.352881632E-03 1.110639271E-02 5.172433282E-03") + mapdl.run("2 3.485685736E-03 1.110981270E-02 4.999255638E-03") + mapdl.run("3 3.615164748E-03 1.111323677E-02 4.823719994E-03") + mapdl.run("4 3.673859471E-03 1.111439119E-02 4.740300611E-03") + mapdl.run("5 3.709417144E-03 1.111407057E-02 4.691582629E-03") mapdl.run("-1")""" pyeblock = """with mapdl.non_interactive: mapdl.run("eblock,19,solid,,6240") mapdl.run("(19i9)") - mapdl.run(" 1 1 1 1 0 0 0 0 20 0 38161 186586 186589 192999 193065 191265 191262 193063 193064") - mapdl.run(" 194712 194731 213866 194716 210305 210306 213993 210310 194715 194730 213865 213995") - mapdl.run(" 1 1 1 1 0 0 0 0 20 0 38162 186586 193065 192999 186589 186781 193066 192935 186784") - mapdl.run(" 194716 213866 194731 194712 195560 213737 195572 195557 194714 213997 213736 194729") - mapdl.run(" 1 1 1 1 0 0 0 0 20 0 38163 186781 193066 192935 186784 186976 193067 192871 186979") - mapdl.run(" 195560 213737 195572 195557 196210 213608 196222 196207 195559 213998 213607 195571") - mapdl.run(" 1 1 1 1 0 0 0 0 20 0 38164 186976 193067 192871 186979 187171 193068 192807 187174") - mapdl.run(" 196210 213608 196222 196207 196860 213479 196872 196857 196209 213999 213478 196221")""" + mapdl.run("1 1 1 1 0 0 0 0 20 0 38161 186586 186589 192999 193065 191265 191262 193063 193064") + mapdl.run("194712 194731 213866 194716 210305 210306 213993 210310 194715 194730 213865 213995") + mapdl.run("1 1 1 1 0 0 0 0 20 0 38162 186586 193065 192999 186589 186781 193066 192935 186784") + mapdl.run("194716 213866 194731 194712 195560 213737 195572 195557 194714 213997 213736 194729") + mapdl.run("1 1 1 1 0 0 0 0 20 0 38163 186781 193066 192935 186784 186976 193067 192871 186979") + mapdl.run("195560 213737 195572 195557 196210 213608 196222 196207 195559 213998 213607 195571") + mapdl.run("1 1 1 1 0 0 0 0 20 0 38164 186976 193067 192871 186979 187171 193068 192807 187174") + mapdl.run("196210 213608 196222 196207 196860 213479 196872 196857 196209 213999 213478 196221")""" pycmblock = """with mapdl.non_interactive: mapdl.run("CMBLOCK,PRESSURE_AREAS,NODE, 48") mapdl.run("(8i10)") - mapdl.run(" 1688 1689 1690 1691 1700 1701 1702 1703") - mapdl.run(" 1704 1705 1706 1707 1708 1709 1710 1711") - mapdl.run(" 1712 1721 1723 1731 1736 1754 1755 1756") - mapdl.run(" 1757 1758 1759 1760 1761 1762 1763 1764") - mapdl.run(" 1765 1766 1767 1768 1769 1802 1803 1804") - mapdl.run(" 1805 1806 1807 1808 1809 1831 1832 1833")""" + mapdl.run("1688 1689 1690 1691 1700 1701 1702 1703") + mapdl.run("1704 1705 1706 1707 1708 1709 1710 1711") + mapdl.run("1712 1721 1723 1731 1736 1754 1755 1756") + mapdl.run("1757 1758 1759 1760 1761 1762 1763 1764") + mapdl.run("1765 1766 1767 1768 1769 1802 1803 1804") + mapdl.run("1805 1806 1807 1808 1809 1831 1832 1833")""" block_commands = ["nblock", "eblock", "cmblock"] From 83296c19cf95021dcf77276ef1d562f4f38ed055 Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 15:36:37 +0200 Subject: [PATCH 37/70] Avoiding too early exit in mapdl.input --- src/ansys/mapdl/core/mapdl_grpc.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/ansys/mapdl/core/mapdl_grpc.py b/src/ansys/mapdl/core/mapdl_grpc.py index e0a17efb0a..d3dd2f15a7 100644 --- a/src/ansys/mapdl/core/mapdl_grpc.py +++ b/src/ansys/mapdl/core/mapdl_grpc.py @@ -1812,11 +1812,6 @@ def input( if not self._apdl_log.closed: self._apdl_log.write(tmp_dat) - # Escaping early if inside non_interactive context - if self._store_commands: - self._stored_commands.append(tmp_dat.splitlines()[1]) - return None - if self._local: local_path = self.directory tmp_name_path = os.path.join(local_path, tmp_name) @@ -1825,6 +1820,11 @@ def input( else: self._upload_raw(tmp_dat.encode(), tmp_name) + # Escaping early if inside non_interactive context + if self._store_commands: + self._stored_commands.append(tmp_dat.splitlines()[1]) + return None + request = pb_types.InputFileRequest(filename=tmp_name) # even though we don't care about the output, we still @@ -1872,10 +1872,6 @@ def _get_file_path(self, fname: str, progress_bar: bool = False) -> str: overwriting the MAPDL directory copy. """ - if self._store_commands: - # Exiting early if in non-interactive mode. - return fname - if os.path.isdir(fname): raise ValueError( f"`fname` should be a full file path or name, not the directory '{fname}'." @@ -1901,9 +1897,13 @@ def _get_file_path(self, fname: str, progress_bar: bool = False) -> str: if os.path.isfile(fname): # And it exists filename = os.path.join(os.getcwd(), fname) - elif fname in self.list_files(): + elif not self._store_commands and fname in self.list_files(): # It exists in the Mapdl working directory filename = os.path.join(self.directory, fname) + elif self._store_commands: + # Assuming that in non_interactive we have uploaded the file + # manually. + filename = os.path.join(self.directory, fname) else: # Finally raise FileNotFoundError(f"Unable to locate filename '{fname}'") @@ -1914,10 +1914,15 @@ def _get_file_path(self, fname: str, progress_bar: bool = False) -> str: self.upload(ffullpath, progress_bar=progress_bar) filename = fname - elif fname in self.list_files(): + elif not self._store_commands and fname in self.list_files(): # It exists in the Mapdl working directory filename = fname + elif self._store_commands: + # Assuming that in non_interactive, the file exists already in + # the Mapdl working directory + filename = fname + else: raise FileNotFoundError(f"Unable to locate filename '{fname}'") @@ -3340,7 +3345,7 @@ def _check_session_id(self): if pymapdl_session_id is None or self._mapdl_session_id is None: return elif pymapdl.RUNNING_TESTS or self._strict_session_id_check: - if pymapdl_session_id != self._mapdl_session_id: + if pymapdl_session_id != self._mapdl_session_id and False: self._log.error("The session ids do not match") raise DifferentSessionConnectionError( f"Local MAPDL session ID '{pymapdl_session_id}' is different from MAPDL session ID '{self._mapdl_session_id}." From a5c73f94baa8934ec12006ac13fcab640915cdc0 Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 15:50:38 +0200 Subject: [PATCH 38/70] Removing check --- src/ansys/mapdl/core/mapdl_grpc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/mapdl_grpc.py b/src/ansys/mapdl/core/mapdl_grpc.py index d3dd2f15a7..acdf4db41a 100644 --- a/src/ansys/mapdl/core/mapdl_grpc.py +++ b/src/ansys/mapdl/core/mapdl_grpc.py @@ -3345,7 +3345,7 @@ def _check_session_id(self): if pymapdl_session_id is None or self._mapdl_session_id is None: return elif pymapdl.RUNNING_TESTS or self._strict_session_id_check: - if pymapdl_session_id != self._mapdl_session_id and False: + if pymapdl_session_id != self._mapdl_session_id: self._log.error("The session ids do not match") raise DifferentSessionConnectionError( f"Local MAPDL session ID '{pymapdl_session_id}' is different from MAPDL session ID '{self._mapdl_session_id}." From 55fd432bffc10ce62a748c19e8a551d8d5549577 Mon Sep 17 00:00:00 2001 From: germa89 Date: Thu, 19 Oct 2023 14:10:19 +0000 Subject: [PATCH 39/70] Update the image cache --- .../plot_incomplete_nodal_selection.png | Bin 24046 -> 47891 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/.image_cache/plot_incomplete_nodal_selection.png b/tests/.image_cache/plot_incomplete_nodal_selection.png index 31ba437e1a063a0cfd5a4148dbcb09cd4ca8f718..d4bd491746c9ae6ce12d5ab88329515be09e7c6f 100644 GIT binary patch literal 47891 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 QgYtWBscNefD%m{wA1;?R1ONa4 literal 24046 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¥Ch8I8qS;x) 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 Date: Thu, 19 Oct 2023 16:30:29 +0200 Subject: [PATCH 40/70] removing coda codacy warnings --- src/ansys/mapdl/core/_commands/apdl/parameter_definition.py | 1 - src/ansys/mapdl/core/convert.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py b/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py index 3efa3fab43..0504307d11 100644 --- a/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py +++ b/src/ansys/mapdl/core/_commands/apdl/parameter_definition.py @@ -524,7 +524,6 @@ def parres(self, lab="", fname="", ext="", **kwargs): fname = self._get_file_name( fname=fname, ext=ext, default_extension="parm" ) # Although documentation says `PARM` - file_, ext_, _ = self._decompose_fname(fname) if self._mode == "grpc": # grpc mode if self.is_local: diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index f0ada56aea..59e5e2add4 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -636,7 +636,7 @@ def initialize_mapdl_object(self, loglevel, exec_file): mapdl_arguments.append(f"use_vtk={bool(self.use_vtk)}") if self.check_parameter_names is not None and not self.check_parameter_names: - mapdl_arguments.append(f"check_parameter_names=False") + mapdl_arguments.append("check_parameter_names=False") line = f'{self.obj_name} = launch_mapdl({", ".join(mapdl_arguments)})' self.lines.append(line) From 198ea257fb0b1dc603a93769c6f49f09a264abbc Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 20:05:02 +0200 Subject: [PATCH 41/70] Adding missing arguments --- .../core/_commands/preproc/special_purpose.py | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/ansys/mapdl/core/_commands/preproc/special_purpose.py b/src/ansys/mapdl/core/_commands/preproc/special_purpose.py index 23c962db2d..5bc016c248 100644 --- a/src/ansys/mapdl/core/_commands/preproc/special_purpose.py +++ b/src/ansys/mapdl/core/_commands/preproc/special_purpose.py @@ -1003,7 +1003,16 @@ def xfdata(self, enrichmentid="", elemnum="", nodenum="", phi="", **kwargs): command = f"XFDATA,{enrichmentid},{elemnum},{nodenum},{phi}" return self.run(command, **kwargs) - def xfenrich(self, enrichmentid="", compname="", matid="", **kwargs): + def xfenrich( + self, + enrichmentid="", + compname="", + matid="", + method="", + radius="", + snaptoler="", + **kwargs, + ): """Defines parameters associated with crack propagation using XFEM APDL Command: XFENRICH @@ -1025,6 +1034,19 @@ def xfenrich(self, enrichmentid="", compname="", matid="", **kwargs): the initial crack. If 0 or not specified, the initial crack is assumed to be free of cohesive zone behavior. + method + PHAN -- Use phantom-node-based XFEM (default). + SING -- Use singularity-based XFEM. + + radius + Radius defining the region around the crack tip encompassing the + set of elements to be influenced by the crack-tip singularity effects. + Default = 0.0. Used only in singularity-based XFEM. + + snaptoler + Snap tolerance to snap the crack tip to the closest crack face along + the extension direction. Default = 1.0E-6. Used only in singularity-based XFEM. + Notes ----- If MatID is specified, the cohesive zone behavior is described by the @@ -1032,7 +1054,7 @@ def xfenrich(self, enrichmentid="", compname="", matid="", **kwargs): This command is valid in PREP7 (/PREP7) only. """ - command = f"XFENRICH,{enrichmentid},{compname},{matid}" + command = f"XFENRICH,{enrichmentid},{compname},{matid}, {method}, {radius}, {snaptoler}" return self.run(command, **kwargs) def xflist(self, enrichmentid="", **kwargs): From 239186c2110c666727a17d108862e1831dc6d901 Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 20:05:21 +0200 Subject: [PATCH 42/70] Fixing argument order --- src/ansys/mapdl/core/_commands/post26_/special.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/_commands/post26_/special.py b/src/ansys/mapdl/core/_commands/post26_/special.py index 37e75e9d3d..3a899bf393 100644 --- a/src/ansys/mapdl/core/_commands/post26_/special.py +++ b/src/ansys/mapdl/core/_commands/post26_/special.py @@ -330,7 +330,7 @@ def rpsd( See POST26 - Response Power Spectral Density in the Mechanical APDL Theory Reference for more information on these equations. """ - command = f"RPSD,{ir},{ia},{ib},{itype},{datum},{name},{signif}" + command = f"RPSD,{ir},{ia},{ib},{itype},{datum},{name},,{signif}" return self.run(command, **kwargs) def smooth( From 98acb608f6bf1c60f3604efda2974ce10315e279 Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 20:06:33 +0200 Subject: [PATCH 43/70] Adding missing commands to ignored. Not scaping non_interactive after *VWRITE format. --- src/ansys/mapdl/core/convert.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index 59e5e2add4..34b6c8bd0a 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -73,6 +73,7 @@ "RACE": (), # RACE, "REAL": (), # REALVAR, "REME": (), # REMESH, + "RPSD": (), # RPSD "SECR": (), # SECREAD "SECW": (), # SECWRITE "SESY": (), # SESYMM, @@ -93,6 +94,7 @@ "/LIN", # Until we merge 2432 "/LAR", # Until we merge 2432 "/TYP", # Until we merge 2432 + "/DSC", # Until we merge 2432 ] @@ -545,7 +547,6 @@ def __init__( } # Commands where you need to count the number of lines. _NON_INTERACTIVE_COMMANDS = { - "*CRE": "*CREATE", "*VWR": "*VWRITE", "*VRE": "*VREAD", } @@ -769,7 +770,7 @@ def translate_line(self, line): prev_cmd = self.lines.pop(-1) self.start_non_interactive() new_prev_cmd = ( - " " + prev_cmd + self.indent + prev_cmd ) # Since we are writing in self.lines we need to add the indentation by ourselves. self.lines.append(new_prev_cmd) self.store_run_command( @@ -856,10 +857,6 @@ def translate_line(self, line): + "The previous line is: \n%s\n\n" % self.lines[-1] ) self.store_run_command(line) - if ( - not self._in_block - ): # To escape cmds that require (XX) but they are not in block - self.end_non_interactive() return elif cmd_caps_short == "*USE" and self.macros_as_functions: func_name = items[1].strip() @@ -946,7 +943,7 @@ def start_function(self, func_name): self.store_empty_line() self._infunction = True spacing = " " * (len(func_name) + 5) - line = "def %s(%s," % ( + line = self.indent + "def %s(%s," % ( func_name, ", ".join(["ARG%d=''" % i for i in range(1, 7)]), ) @@ -1070,9 +1067,9 @@ def start_non_interactive(self): def end_non_interactive(self): self._non_interactive_level -= 1 - if self._non_interactive_level == 0: + self.indent = self.indent[4:] + if self._non_interactive_level <= 0: self.non_interactive = False - self.indent = self.indent[4:] def output_to_file(self, line): """Return if an APDL line is redirecting to a file.""" From ab4705b50ff93378b6b7bad1a448be779bd7ad73 Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 20:25:26 +0200 Subject: [PATCH 44/70] Eliminating unused argument in TBDATA --- src/ansys/mapdl/core/examples/verif/vm221.dat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/examples/verif/vm221.dat b/src/ansys/mapdl/core/examples/verif/vm221.dat index 523bbcbb5e..07f4b5ac29 100755 --- a/src/ansys/mapdl/core/examples/verif/vm221.dat +++ b/src/ansys/mapdl/core/examples/verif/vm221.dat @@ -24,7 +24,7 @@ C6=70E3 !MPA, [MARTENSITE MODULUS] C7=0 !M = 0, SYMMETRICAL BEHAVIOR TB,SMA,1,,7,MEFF -TBDATA,1,C1,C2,C3,C4,C5,C6,C7 +TBDATA,1,C1,C2,C3,C4,C5,C6 BLOCK,0.00,5.00,0.00,5.00,0.00,5.00 ESIZE,5 From 9da409affb889845c9eefbdd34541990946b0b1d Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 20:25:53 +0200 Subject: [PATCH 45/70] Allowing arguments in macro calls. --- src/ansys/mapdl/core/convert.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index 34b6c8bd0a..77d12b5dcd 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -819,11 +819,22 @@ def translate_line(self, line): else: self.start_non_interactive() - if items[0] in self.macros_names: + ## Treating functions + if items[0] in self.macros_names and self.macros_as_functions: # We are calling the function/macro created before. - self.store_python_command(f"{items[0]}()") + func_name = items[0].strip() + + args = self._parse_arguments(items[1:]) + self.store_python_command(f"{func_name}({args})") return + if cmd_caps_short == "*USE" and self.macros_as_functions: + func_name = items[1].strip() + if func_name in self._functions: + args = ", ".join(items[2:]) + self.lines.append(f"{func_name}({args})") + return + if cmd_caps == "/PREP7": return self.store_command("prep7", []) @@ -858,12 +869,6 @@ def translate_line(self, line): ) self.store_run_command(line) return - elif cmd_caps_short == "*USE" and self.macros_as_functions: - func_name = items[1].strip() - if func_name in self._functions: - args = ", ".join(items[2:]) - self.lines.append(f"{func_name}({args})") - return # check if a line is setting a variable if "=" in items[0]: # line sets a variable: @@ -1020,8 +1025,7 @@ def store_python_command(self, command): line = f"{self.indent}{command}" self.lines.append(line) - def store_command(self, function, parameters): - """Stores a valid pyansys function with parameters""" + def _parse_arguments(self, parameters): parsed_parameters = [] for parameter in parameters: parameter = parameter.strip() @@ -1037,7 +1041,12 @@ def store_command(self, function, parameters): parameter = parameter[1:-1] parsed_parameters.append(f'"{parameter}"') - parameter_str = ", ".join(parsed_parameters) + return ", ".join(parsed_parameters) + + def store_command(self, function, parameters): + """Stores a valid pyansys function with parameters""" + parameter_str = self._parse_arguments(parameters) + if self.comment: line = "%s%s.%s(%s) # %s" % ( self.indent, From 0300d57a33f7c7dfe49cf4e8be7536348f3fdd13 Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 21:48:21 +0200 Subject: [PATCH 46/70] Taking into account leading chars --- src/ansys/mapdl/core/convert.py | 35 ++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index 77d12b5dcd..d863a49d13 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -532,7 +532,7 @@ def __init__( if self._add_imports: self.initialize_mapdl_object(loglevel, exec_file) - self._valid_commands = dir(Commands) + self._valid_commands = self._get_valid_pymapdl_methods_short() self._block_commands = { "NBLO": "NBLOCK", "EBLO": "EBLOCK", @@ -920,20 +920,27 @@ def translate_line(self, line): self.store_run_command(line.strip()) elif self.use_function_names: + # Takign into account the leading characters if command[0] == "/": slash_command = f"slash{command[1:]}" - if slash_command in dir(Commands): + if slash_command in self._valid_commands: command = slash_command else: command = command[1:] elif command[0] == "*": star_command = f"star{command[1:]}" - if star_command in dir(Commands): + if star_command in self._valid_commands: command = star_command else: command = command[1:] + # Some commands are abbreviated (only 4 letters) + if command not in dir(Commands): + command = self.find_match(command) + + # Storing self.store_command(command, parameters) + else: self.store_run_command(line.strip()) @@ -1144,6 +1151,28 @@ def _get_items(self, line_): return items + def _get_valid_pymapdl_methods_short(self): + pymethods = dir(Commands) + + reduced_list = [] + for each_method in pymethods: + if not re.match(r"^[\*~/A-Za-z]\w*$", each_method): + continue + if each_method.startswith("slash"): + reduced_list.append(each_method[:9]) + elif each_method.startswith("star"): + reduced_list.append(each_method[:8]) + else: + reduced_list.append(each_method[:4]) + return reduced_list + + def find_match(self, cmd): + pymethods = sorted(dir(Commands)) + + for each in pymethods: + if each.startswith(cmd): + return each + import click From 70555ed70537aaf5281577f8665dceb66c7e3976 Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 21:50:25 +0200 Subject: [PATCH 47/70] Adding missing argument to HEMIOPT --- src/ansys/mapdl/core/_commands/aux12_/radiosity_solver.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/_commands/aux12_/radiosity_solver.py b/src/ansys/mapdl/core/_commands/aux12_/radiosity_solver.py index 7201c54824..0ac25dfa89 100644 --- a/src/ansys/mapdl/core/_commands/aux12_/radiosity_solver.py +++ b/src/ansys/mapdl/core/_commands/aux12_/radiosity_solver.py @@ -9,8 +9,11 @@ def hemiopt(self, hres="", **kwargs): hres Hemicube resolution. Increase value to increase the accuracy of the view factor calculation. Defaults to 10. + + tolerance + Tolerance value that controls whether or not facets are subdivided in view factor calculations to increase view factor accuracy. TOLERANCE is closely related to the spacing between facets. Defaults to 1e-6. """ - command = f"HEMIOPT,{hres}" + command = f"HEMIOPT,{hres},{tolerance}" return self.run(command, **kwargs) def radopt( From f5b23e7aad865c7ca8cb9c4fa9697b4dc594140a Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 22:04:06 +0200 Subject: [PATCH 48/70] Adding more command to empty spaces --- src/ansys/mapdl/core/convert.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index d863a49d13..71dd14162a 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -44,6 +44,8 @@ "ASBL": (), # ASBL, "ATAN": (), # ATAN, "BCSO": (), # BCSOPTION, + "CORI": (), # CORIOLIS + "CDRE": (), # CDREAD "CLOG": (), # CLOG, "CONJ": (), # CONJUG, "DERI": (), # DERIV, @@ -71,6 +73,7 @@ "QRDO": (), # QRDOPT, "QUOT": (), # QUOT, "RACE": (), # RACE, + "RDEC": (), # RDEC "REAL": (), # REALVAR, "REME": (), # REMESH, "RPSD": (), # RPSD @@ -95,6 +98,7 @@ "/LAR", # Until we merge 2432 "/TYP", # Until we merge 2432 "/DSC", # Until we merge 2432 + # CDREAD # commented above ] From 5c32b2db2e7f84e2888383284d6cea00fc56845e Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 22:04:53 +0200 Subject: [PATCH 49/70] removing extra argument --- src/ansys/mapdl/core/examples/verif/vm285.dat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/examples/verif/vm285.dat b/src/ansys/mapdl/core/examples/verif/vm285.dat index 8c06bd0da1..c33f584b02 100644 --- a/src/ansys/mapdl/core/examples/verif/vm285.dat +++ b/src/ansys/mapdl/core/examples/verif/vm285.dat @@ -46,7 +46,7 @@ A,1,2,3,4,7 A,7,4,5,6 AGLUE,ALL -KSCON,2,A/20,0,12,,10 ! CRACK TIP ELEMENTS +KSCON,2,A/20,0,12,, ! CRACK TIP ELEMENTS ESIZE,0.3 AMESH,1 From 3af991aaae8ac2e9f79e5b1f3ae68c5253d4d769 Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 22:06:08 +0200 Subject: [PATCH 50/70] removing extra argument --- src/ansys/mapdl/core/examples/verif/vm287.dat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/examples/verif/vm287.dat b/src/ansys/mapdl/core/examples/verif/vm287.dat index 8fec708652..a3aec45a2d 100644 --- a/src/ansys/mapdl/core/examples/verif/vm287.dat +++ b/src/ansys/mapdl/core/examples/verif/vm287.dat @@ -70,7 +70,7 @@ ALLSEL XFENRICH,ENRICH1,TESTCMP,1 FLST,3,2,8 FITEM,3,0.0,5.0,0 -FITEM,3,5.0,5.0,0,0 +FITEM,3,5.0,5.0,0 XFDATA,ENRICH1,P51X ALLSEL /OUT From a4d12f0b92a026de03508029522e568b669ccfec Mon Sep 17 00:00:00 2001 From: German Date: Thu, 19 Oct 2023 22:09:03 +0200 Subject: [PATCH 51/70] Adding missing argument to PSDGRAPH --- .../core/_commands/solution/spectrum_options.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ansys/mapdl/core/_commands/solution/spectrum_options.py b/src/ansys/mapdl/core/_commands/solution/spectrum_options.py index ff65b77274..55ecbf445b 100644 --- a/src/ansys/mapdl/core/_commands/solution/spectrum_options.py +++ b/src/ansys/mapdl/core/_commands/solution/spectrum_options.py @@ -669,7 +669,7 @@ def psdfrq( command = f"PSDFRQ,{tblno1},{tblno2},{freq1},{freq2},{freq3},{freq4},{freq5},{freq6},{freq7}" return self.run(command, **kwargs) - def psdgraph(self, tblno1="", tblno2="", **kwargs): + def psdgraph(self, tblno1="", tblno2="", displaykey="", **kwargs): """Displays input PSD curves APDL Command: PSDGRAPH @@ -683,6 +683,14 @@ def psdgraph(self, tblno1="", tblno2="", **kwargs): Second PSD table number to display. TBLNO2 is used only in conjunction with the COVAL or the QDVAL commands. + displaykey + Key to display the points markers and numbering: + + 0 - Display points markers and numbering (default). + 1 - Display points numbering only. + 2 - Display points markers only. + 3 - No points markers or numbering. + Notes ----- The input PSD tables are displayed in log-log format as dotted lines. @@ -699,7 +707,7 @@ def psdgraph(self, tblno1="", tblno2="", **kwargs): This command is valid in any processor. """ - command = f"PSDGRAPH,{tblno1},{tblno2}" + command = f"PSDGRAPH,{tblno1},{tblno2},{displaykey}" return self.run(command, **kwargs) def psdres(self, lab="", relkey="", **kwargs): From 10f8eff662a92d5b5afbd37e6e4a5451be3c52be Mon Sep 17 00:00:00 2001 From: German Date: Fri, 20 Oct 2023 10:42:26 +0200 Subject: [PATCH 52/70] * Fixing no exit from interactive. * Using f string for `mapdl.run` with ARGXs. --- src/ansys/mapdl/core/convert.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index 71dd14162a..96c48b6129 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -994,16 +994,15 @@ def store_run_command(self, command, run_underscored=False): arg = "ARG%d" % i c = 0 if arg in command: - command = command.replace(arg, "{%d:s}" % c) + command = command.replace(arg, "{" + f"{arg}" + "}") args.append(arg) c += 1 - line = '%s%s.%srun("%s".format(%s))' % ( + line = '%s%s.%srun(f"%s")' % ( self.indent, self.obj_name, underscore, command, - ", ".join(args), ) elif self.comment: @@ -1088,8 +1087,7 @@ def start_non_interactive(self): def end_non_interactive(self): self._non_interactive_level -= 1 self.indent = self.indent[4:] - if self._non_interactive_level <= 0: - self.non_interactive = False + self.non_interactive = False def output_to_file(self, line): """Return if an APDL line is redirecting to a file.""" From 83a17452bf8d004eb752f222b886970495d96cf8 Mon Sep 17 00:00:00 2001 From: German Date: Fri, 20 Oct 2023 12:05:56 +0200 Subject: [PATCH 53/70] * Adding FORCED_MAPPING for exceptions. * Improving entry/exit non-interactive commands * Reducing the trailing space. --- src/ansys/mapdl/core/convert.py | 53 +++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index 96c48b6129..f11a2e47e7 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -101,6 +101,11 @@ # CDREAD # commented above ] +FORCED_MAPPING = { + # Forced mapping between MAPDL and PyMAPDL + "SECT": "sectype", # Because it is shadowed by `sectinqr` +} + def convert_script( filename_in, @@ -836,7 +841,7 @@ def translate_line(self, line): func_name = items[1].strip() if func_name in self._functions: args = ", ".join(items[2:]) - self.lines.append(f"{func_name}({args})") + self.store_python_command(f"{func_name}({args})") return if cmd_caps == "/PREP7": @@ -925,22 +930,28 @@ def translate_line(self, line): elif self.use_function_names: # Takign into account the leading characters - if command[0] == "/": - slash_command = f"slash{command[1:]}" - if slash_command in self._valid_commands: - command = slash_command - else: - command = command[1:] - elif command[0] == "*": - star_command = f"star{command[1:]}" - if star_command in self._valid_commands: - command = star_command - else: - command = command[1:] - - # Some commands are abbreviated (only 4 letters) - if command not in dir(Commands): - command = self.find_match(command) + if command.upper() in FORCED_MAPPING: + # Checking exceptions/forced mapping + command = FORCED_MAPPING[command.upper()] + + else: + # Looking for a suitable candidate. + if command[0] == "/": + slash_command = f"slash{command[1:]}" + if slash_command in self._valid_commands: + command = slash_command + else: + command = command[1:] + elif command[0] == "*": + star_command = f"star{command[1:]}" + if star_command in self._valid_commands: + command = star_command + else: + command = command[1:] + + # Some commands are abbreviated (only 4 letters) + if command not in dir(Commands): + command = self.find_match(command) # Storing self.store_command(command, parameters) @@ -988,6 +999,9 @@ def store_run_command(self, command, run_underscored=False): else: underscore = "" + # Removing trailing/leading spaces + command = command.strip() + if self._infunction and "ARG" in command: args = [] for i in range(1, 19): @@ -1086,8 +1100,9 @@ def start_non_interactive(self): def end_non_interactive(self): self._non_interactive_level -= 1 - self.indent = self.indent[4:] - self.non_interactive = False + if self._non_interactive_level <= 0: + self.indent = self.indent[4:] + self.non_interactive = False def output_to_file(self, line): """Return if an APDL line is redirecting to a file.""" From 0af13154938c904ea006d47487b2fa99c2561835 Mon Sep 17 00:00:00 2001 From: German Date: Fri, 20 Oct 2023 12:54:36 +0200 Subject: [PATCH 54/70] * Fix issue when non finding pymapdl equivalent, it gets none. * Commenting out /exit in non_interactive --- src/ansys/mapdl/core/convert.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index f11a2e47e7..2404fccff3 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -755,6 +755,9 @@ def translate_line(self, line): self.end_non_interactive() return + if "/EXI" in cmd_caps.upper() and self.non_interactive: + self.store_command("com", [f"Skipping: {line}"]) + if self.output_to_file(line): if self.verification_example and "SCRATCH" in line.upper(): self.store_command("com", [f"Skipping: {line}"]) @@ -899,7 +902,7 @@ def translate_line(self, line): # check valid command if ( self._pymapdl_command(command) not in self._valid_commands - or cmd_caps_short in self._non_interactive_commands + and cmd_caps_short in self._non_interactive_commands ): if cmd_caps_short in self._non_interactive_commands: if cmd_caps_short in self._block_commands: @@ -950,7 +953,9 @@ def translate_line(self, line): command = command[1:] # Some commands are abbreviated (only 4 letters) - if command not in dir(Commands): + from ansys.mapdl.core import Mapdl + + if command not in dir(Mapdl): command = self.find_match(command) # Storing @@ -1190,6 +1195,8 @@ def find_match(self, cmd): if each.startswith(cmd): return each + return cmd + import click From ccd1e068fca247e2dc3e5d07875e292f2c4c64b0 Mon Sep 17 00:00:00 2001 From: German Date: Fri, 20 Oct 2023 13:07:54 +0200 Subject: [PATCH 55/70] * Keeping empty lines * Making sure we account for commands with empty arguments with spaces in them. * Fix error that `find_match` returns always something and it is used to create the mapdl method (which might not exist) --- src/ansys/mapdl/core/convert.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index 2404fccff3..a97d01e6e5 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -701,6 +701,8 @@ def translate_line(self, line): self.comment = self.comment.lstrip() if not line: + # Keeping empty lines + self.lines.append("") return # Cleaning ending empty arguments. @@ -794,7 +796,7 @@ def translate_line(self, line): # Skipping conversion if command has empty arguments and there is ",," in the call if ( cmd_caps_short in COMMANDS_WITH_EMPTY_ARGS - and ",," in line_with_trailing_commas + and ",," in line_with_trailing_commas.replace(" ", "") ): self.store_run_command(line.strip()) return @@ -959,7 +961,10 @@ def translate_line(self, line): command = self.find_match(command) # Storing - self.store_command(command, parameters) + if command: + self.store_command(command, parameters) + else: # find_match can return None + self.store_run_command(line.strip()) else: self.store_run_command(line.strip()) @@ -1195,8 +1200,6 @@ def find_match(self, cmd): if each.startswith(cmd): return each - return cmd - import click From 1d0d33117e6d63dabc0744b3d007b8d498ff47af Mon Sep 17 00:00:00 2001 From: German Date: Fri, 20 Oct 2023 18:01:37 +0200 Subject: [PATCH 56/70] Removing extra arguments. --- src/ansys/mapdl/core/examples/verif/vm227.dat | 2 +- src/ansys/mapdl/core/examples/verif/vm273.dat | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ansys/mapdl/core/examples/verif/vm227.dat b/src/ansys/mapdl/core/examples/verif/vm227.dat index eacfe91d18..7f8fec704c 100755 --- a/src/ansys/mapdl/core/examples/verif/vm227.dat +++ b/src/ansys/mapdl/core/examples/verif/vm227.dat @@ -28,7 +28,7 @@ SFL,8,RDSF,1, ,1, FINISH /AUX12 STEF,0.119E-10 !SET STEFAN-BOLTZMAN CONSTANT FOR MODEL -hemiopt,,,,,,,,,,,,,,,,,,,0 +hemiopt TOFFST,100 !SET TEMPERATURE OFFSET RADOPT,,0.1,2,1000,0.1,0.1 !SET RADIOSITY OPTIONS SPCTEMP,1,0.E+00 !SET TEMPERATURE FOR RADIATION TO SPACE diff --git a/src/ansys/mapdl/core/examples/verif/vm273.dat b/src/ansys/mapdl/core/examples/verif/vm273.dat index a4f5ed1dcf..f0145eed29 100755 --- a/src/ansys/mapdl/core/examples/verif/vm273.dat +++ b/src/ansys/mapdl/core/examples/verif/vm273.dat @@ -27,7 +27,7 @@ C6=70E3 !MPA, [MARTENSITE MODULUS] C7=0 ! M = 0, SYMMETRICAL BEHAVIOR TB,SMA,1,,7,MEFF -TBDATA,1,C1,C2,C3,C4,C5,C6,C7 +TBDATA,1,C1,C2,C3,C4,C5,C6 BLOCK,0.00,10.00,0.00,10.00,0.00,10.00 ESIZE,10 From 5811412085df3152dc1c8147f981ad8a4d409945 Mon Sep 17 00:00:00 2001 From: German Date: Fri, 20 Oct 2023 18:02:21 +0200 Subject: [PATCH 57/70] Adding missing arguments --- .../mapdl/core/_commands/preproc/special_purpose.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ansys/mapdl/core/_commands/preproc/special_purpose.py b/src/ansys/mapdl/core/_commands/preproc/special_purpose.py index 5bc016c248..7f80d5b4b4 100644 --- a/src/ansys/mapdl/core/_commands/preproc/special_purpose.py +++ b/src/ansys/mapdl/core/_commands/preproc/special_purpose.py @@ -969,7 +969,9 @@ def sstate( command = f"SSTATE,{action},{cm_name},{val1},{val2},{val3},{val4},{val5},{val6},{val7},{val8},{val9}" return self.run(command, **kwargs) - def xfdata(self, enrichmentid="", elemnum="", nodenum="", phi="", **kwargs): + def xfdata( + self, enrichmentid="", lsm="", elemnum="", nodenum="", phi="", psi="", **kwargs + ): """Defines a crack in the model by specifying nodal level set values APDL Command: XFDATA @@ -993,6 +995,10 @@ def xfdata(self, enrichmentid="", elemnum="", nodenum="", phi="", **kwargs): phi Signed normal distance of the node from the crack. + psi + Signed normal distance of the node from the crack tip (or crack front). + Used only in the singularity- based XFEM method. + Notes ----- Issue the XFDATA command multiple times as needed to specify nodal @@ -1000,7 +1006,7 @@ def xfdata(self, enrichmentid="", elemnum="", nodenum="", phi="", **kwargs): This command is valid in PREP7 (/PREP7) only. """ - command = f"XFDATA,{enrichmentid},{elemnum},{nodenum},{phi}" + command = f"XFDATA,{enrichmentid},{lsm},{elemnum},{nodenum},{phi},{psi}" return self.run(command, **kwargs) def xfenrich( From 8a02235f1cf041a5fc2aa2ec7ba907bc96613fe5 Mon Sep 17 00:00:00 2001 From: German Date: Fri, 20 Oct 2023 18:02:39 +0200 Subject: [PATCH 58/70] Adding golden tests --- tests/test_convert.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/test_convert.py b/tests/test_convert.py index 631667bbcf..c2a8234b6c 100644 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -138,6 +138,25 @@ *END *USE,SLV""" +DO_CONVERSION = """with mapdl.non_interactive: + mapdl.run("*DO,I,1,81") # REPEAT MACRO EXECUTION""" + +GOLDEN_TESTS = { + "/DELETE,TABLE_1": 'mapdl.slashdelete("TABLE_1")', + "PROD,4,3, , ,FORCE , , ,-1.0,1,1,": 'mapdl.run("PROD,4,3, , ,FORCE , , ,-1.0,1,1")', + "ALLSEL,ALL": 'mapdl.allsel("ALL")', + "/EXIT,NOSAVE": 'mapdl.exit("NOSAVE")', + "": "", + "*DO,I,1,81 ! REPEAT MACRO EXECUTION": DO_CONVERSION, + " *USE,LOAD ! EXECUTE MACRO": 'mapdl.use("LOAD") # EXECUTE MACRO', + "*ENDDO": 'mapdl.run("*ENDDO")', + "SECT,1,SHELL": 'mapdl.sectype(1, "SHELL")', + "SECD,.00005,1 ! PLATE THICKNESS": "mapdl.secdata(.00005, 1) # PLATE THICKNESS", + "/show, asdf": 'mapdl.show("asdf")', + "*STAT,UXFEA2 ": 'mapdl.stat("UXFEA2")', + "/AXLAB,X,NORMALIZED TIME,TAU=ALPHA**2*D*t": 'mapdl.axlab("X", "NORMALIZED TIME,TAU=ALPHA**2*D*t")', +} + def test_convert_no_use_function_names(tmpdir): vm_file = examples.vmfiles["vm1"] @@ -553,6 +572,11 @@ def test_macros_call(): assert "myfunc()" in conv_cmd +@pytest.mark.parametrize("mapdl_cmd", GOLDEN_TESTS.keys()) +def test_golden(mapdl_cmd): + assert GOLDEN_TESTS[mapdl_cmd] == convert_apdl_block(mapdl_cmd, only_commands=True) + + ## CLI testing From 15c629a25adac1d874838ea6d1242b09ba65513d Mon Sep 17 00:00:00 2001 From: German Date: Fri, 20 Oct 2023 18:03:27 +0200 Subject: [PATCH 59/70] Adding /AXLAB specific behaviour. Fixing not finding commands in _valid_commands. --- src/ansys/mapdl/core/convert.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index a97d01e6e5..1dd658e20f 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -88,6 +88,7 @@ "SURE": (), # SURESU, "THOP": (), # THOPT, "TINT": (), # TINTP, + "XFDA": (), # XFDATA } @@ -99,6 +100,7 @@ "/TYP", # Until we merge 2432 "/DSC", # Until we merge 2432 # CDREAD # commented above + "AXLAB", # because it can include commas in the arguments. ] FORCED_MAPPING = { @@ -808,7 +810,12 @@ def translate_line(self, line): if cmd_caps_short == "/TIT": # /TITLE parameters = line.split(",")[1:] - return self.store_command("title", ["".join(parameters).strip()]) + return self.store_command("title", [",".join(parameters).strip()]) + + if cmd_caps_short == "/AXL": # /AXLAB + parameters = line.split(",")[1:] + parameters_ = [parameters[0], ",".join(parameters[1:])] + return self.store_command("axlab", parameters_) if cmd_caps_short == "*GET": if self.non_interactive: # gives error @@ -942,7 +949,7 @@ def translate_line(self, line): else: # Looking for a suitable candidate. if command[0] == "/": - slash_command = f"slash{command[1:]}" + slash_command = f"slash{command[1:4]}" if slash_command in self._valid_commands: command = slash_command else: @@ -1186,9 +1193,9 @@ def _get_valid_pymapdl_methods_short(self): if not re.match(r"^[\*~/A-Za-z]\w*$", each_method): continue if each_method.startswith("slash"): - reduced_list.append(each_method[:9]) - elif each_method.startswith("star"): reduced_list.append(each_method[:8]) + elif each_method.startswith("star"): + reduced_list.append(each_method[:7]) else: reduced_list.append(each_method[:4]) return reduced_list From 0a9d522a298f4b171e58c4a23ce8a564976f37c3 Mon Sep 17 00:00:00 2001 From: German Date: Fri, 20 Oct 2023 18:15:04 +0200 Subject: [PATCH 60/70] Fixing tests --- src/ansys/mapdl/core/convert.py | 2 +- tests/test_convert.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index 1dd658e20f..a10fafb831 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -955,7 +955,7 @@ def translate_line(self, line): else: command = command[1:] elif command[0] == "*": - star_command = f"star{command[1:]}" + star_command = f"star{command[1:4]}" if star_command in self._valid_commands: command = star_command else: diff --git a/tests/test_convert.py b/tests/test_convert.py index c2a8234b6c..8fc2c3950b 100644 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -153,7 +153,7 @@ "SECT,1,SHELL": 'mapdl.sectype(1, "SHELL")', "SECD,.00005,1 ! PLATE THICKNESS": "mapdl.secdata(.00005, 1) # PLATE THICKNESS", "/show, asdf": 'mapdl.show("asdf")', - "*STAT,UXFEA2 ": 'mapdl.stat("UXFEA2")', + "*STAT,UXFEA2 ": 'mapdl.starstatus("UXFEA2")', "/AXLAB,X,NORMALIZED TIME,TAU=ALPHA**2*D*t": 'mapdl.axlab("X", "NORMALIZED TIME,TAU=ALPHA**2*D*t")', } @@ -415,6 +415,7 @@ def test_commands_with_empty_arguments(): ANTYPE,STATIC,,,""" pycmd = """mapdl.antype("STATIC") # STATIC ANALYSIS mapdl.run("ANTYPE,STATIC,,NON_EMPTY_ARGUMENT") + mapdl.antype("STATIC")""" assert pycmd in convert_apdl_block(cmd, header=False, add_imports=False) @@ -440,7 +441,7 @@ def test_no_macro_as_functions(): APDL_MACRO, macros_as_functions=False, add_imports=False, header=False ) assert "with mapdl.non_interactive" in output - assert ' mapdl.run("*CREATE,SLV")' in output + assert ' mapdl.create("SLV")' in output assert ' mapdl.run("*END")' in output From 8fcbc8243f55c1b0c519a8414a98d0ddaaba46b9 Mon Sep 17 00:00:00 2001 From: germa89 Date: Fri, 20 Oct 2023 16:34:58 +0000 Subject: [PATCH 61/70] Update the image cache --- .../plot_incomplete_nodal_selection.png | Bin 47891 -> 24046 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/.image_cache/plot_incomplete_nodal_selection.png b/tests/.image_cache/plot_incomplete_nodal_selection.png index d4bd491746c9ae6ce12d5ab88329515be09e7c6f..31ba437e1a063a0cfd5a4148dbcb09cd4ca8f718 100644 GIT binary patch literal 24046 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¥Ch8I8qS;x) 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 QgYtWBscNefD%m{wA1;?R1ONa4 From 7c13ad6ce365d1deffa15b9477b374a9a25c0985 Mon Sep 17 00:00:00 2001 From: German Date: Fri, 20 Oct 2023 18:43:39 +0200 Subject: [PATCH 62/70] Empty comment to trigger CICD From 1f750424eccd35cfe987d90f346d1d8c8eb1a785 Mon Sep 17 00:00:00 2001 From: German Date: Fri, 20 Oct 2023 19:06:31 +0200 Subject: [PATCH 63/70] Adding missing import --- src/ansys/mapdl/core/post.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ansys/mapdl/core/post.py b/src/ansys/mapdl/core/post.py index 57022832d0..619fc4dc21 100644 --- a/src/ansys/mapdl/core/post.py +++ b/src/ansys/mapdl/core/post.py @@ -3,6 +3,7 @@ import numpy as np +from ansys.mapdl.core.errors import MapdlRuntimeError from ansys.mapdl.core.misc import supress_logging from ansys.mapdl.core.plotting import general_plotter From 0e385b876f741a4f865e1ab0b6e2c6d0e811f123 Mon Sep 17 00:00:00 2001 From: German Date: Mon, 23 Oct 2023 15:57:55 +0200 Subject: [PATCH 64/70] Improving parsing when using functions --- src/ansys/mapdl/core/convert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index a10fafb831..5104b0f157 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -852,7 +852,7 @@ def translate_line(self, line): if cmd_caps_short == "*USE" and self.macros_as_functions: func_name = items[1].strip() if func_name in self._functions: - args = ", ".join(items[2:]) + args = self._parse_arguments(items[2:]) self.store_python_command(f"{func_name}({args})") return From f7310200b29b1027f8b12dacbbc2f6e60d6ede26 Mon Sep 17 00:00:00 2001 From: German Date: Mon, 23 Oct 2023 15:58:19 +0200 Subject: [PATCH 65/70] Early exiting `*GET` when in `non_interactive`. --- src/ansys/mapdl/core/mapdl.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ansys/mapdl/core/mapdl.py b/src/ansys/mapdl/core/mapdl.py index 2ef3b16aaa..d34a012a44 100644 --- a/src/ansys/mapdl/core/mapdl.py +++ b/src/ansys/mapdl/core/mapdl.py @@ -2801,6 +2801,10 @@ def get( with self.force_output: response = self.run(command, **kwargs) + if self._store_commands: + # Return early in non_interactive + return + value = response.split("=")[-1].strip() if item3: self._log.info( From a4900e27da9d7bd5773229bbae53399742ff6119 Mon Sep 17 00:00:00 2001 From: German Date: Mon, 23 Oct 2023 16:27:56 +0200 Subject: [PATCH 66/70] Improving coverage --- tests/test_convert.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/tests/test_convert.py b/tests/test_convert.py index 8fc2c3950b..5e3f4104f6 100644 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -4,7 +4,11 @@ from ansys.mapdl import core as pymapdl from ansys.mapdl.core import examples -from ansys.mapdl.core.convert import FileTranslator, convert_apdl_block +from ansys.mapdl.core.convert import ( + COMMANDS_TO_NOT_BE_CONVERTED, + FileTranslator, + convert_apdl_block, +) nblock = """nblock,3,,326253 (1i9,3e20.9e3) @@ -391,7 +395,7 @@ def test_repeat(): "ATAN", # ATAN, ], ) -def test_commands_to_not_be_converted(cmd): +def test_empty_arguments_2(cmd): # Checking trailing commas does not avoid conversion assert f'mapdl.run("{cmd}")' not in convert_apdl_block( cmd + ",,", header=False, add_imports=False @@ -636,3 +640,21 @@ def test_converter_cli(tmpdir, run_cli): assert "mapdl.prep7()" in newcontent assert "mapdl.exit()" not in newcontent assert "launch_mapdl" not in newcontent + + +def test_exit_in_non_interactive(): + cmd = """ +*do,i,1,10 +/exit +*enddo""" + output = convert_apdl_block(cmd, only_commands=True) + + assert 'mapdl.run("*do,i,1,10")' in output + assert 'mapdl.com("Skipping: /exit")' in output + assert 'mapdl.run("*enddo")' in output + assert "mapdl.exit" not in output + + +@pytest.mark.parametrize("cmd", COMMANDS_TO_NOT_BE_CONVERTED) +def test_commands_to_not_be_converted(cmd): + assert f'mapdl.run("{cmd}")' in convert_apdl_block(cmd, only_commands=True) From 37a67e78446948e8f113f5f1290e706b5bd3d376 Mon Sep 17 00:00:00 2001 From: German Date: Mon, 23 Oct 2023 16:28:17 +0200 Subject: [PATCH 67/70] Removing unreachable code. --- src/ansys/mapdl/core/convert.py | 48 +++++++++++++++------------------ 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index 5104b0f157..89c3d4528c 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -100,7 +100,6 @@ "/TYP", # Until we merge 2432 "/DSC", # Until we merge 2432 # CDREAD # commented above - "AXLAB", # because it can include commas in the arguments. ] FORCED_MAPPING = { @@ -761,6 +760,7 @@ def translate_line(self, line): if "/EXI" in cmd_caps.upper() and self.non_interactive: self.store_command("com", [f"Skipping: {line}"]) + return if self.output_to_file(line): if self.verification_example and "SCRATCH" in line.upper(): @@ -913,32 +913,26 @@ def translate_line(self, line): self._pymapdl_command(command) not in self._valid_commands and cmd_caps_short in self._non_interactive_commands ): - if cmd_caps_short in self._non_interactive_commands: - if cmd_caps_short in self._block_commands: - self._in_block = True - self._block_count = 0 - self._block_count_target = 0 - - elif cmd_caps_short in self._enum_block_commands: - self._in_block = True - self._block_count = 0 - if cmd_caps_short == "CMBL": # In cmblock - # CMBLOCK,Cname,Entity,NUMITEMS,,,,,KOPT - numitems = int(line.split(",")[3]) - _block_count_target = ( - numitems // 8 + 1 if numitems % 8 != 0 else numitems // 8 - ) - self._block_count_target = ( - _block_count_target + 2 - ) # because the cmd_caps_short line and option line. - - self._block_current_cmd = cmd_caps_short - self.start_non_interactive() - - if self._in_block and cmd_caps_short not in self._non_interactive_commands: - self.store_run_command(original_line.strip()) - else: - self.store_run_command(line.strip()) + if cmd_caps_short in self._block_commands: + self._in_block = True + self._block_count = 0 + self._block_count_target = 0 + + elif cmd_caps_short in self._enum_block_commands: + self._in_block = True + self._block_count = 0 + if cmd_caps_short == "CMBL": # In cmblock + # CMBLOCK,Cname,Entity,NUMITEMS,,,,,KOPT + numitems = int(line.split(",")[3]) + _block_count_target = ( + numitems // 8 + 1 if numitems % 8 != 0 else numitems // 8 + ) + self._block_count_target = ( + _block_count_target + 2 + ) # because the cmd_caps_short line and option line. + + self._block_current_cmd = cmd_caps_short + self.start_non_interactive() elif self.use_function_names: # Takign into account the leading characters From dce3a1c4391e3973f2bc7ed22f75c526d79fb2b7 Mon Sep 17 00:00:00 2001 From: German Date: Tue, 24 Oct 2023 17:09:49 +0200 Subject: [PATCH 68/70] Fixing vwrite command --- src/ansys/mapdl/core/convert.py | 1 + tests/test_convert.py | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/ansys/mapdl/core/convert.py b/src/ansys/mapdl/core/convert.py index 89c3d4528c..1385256e41 100644 --- a/src/ansys/mapdl/core/convert.py +++ b/src/ansys/mapdl/core/convert.py @@ -933,6 +933,7 @@ def translate_line(self, line): self._block_current_cmd = cmd_caps_short self.start_non_interactive() + self.store_run_command(line.strip()) elif self.use_function_names: # Takign into account the leading characters diff --git a/tests/test_convert.py b/tests/test_convert.py index 5e3f4104f6..6f088cdeda 100644 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -658,3 +658,14 @@ def test_exit_in_non_interactive(): @pytest.mark.parametrize("cmd", COMMANDS_TO_NOT_BE_CONVERTED) def test_commands_to_not_be_converted(cmd): assert f'mapdl.run("{cmd}")' in convert_apdl_block(cmd, only_commands=True) + + +def test_vwrite(): + cmd = """*VWRITE ! WRITE OUTPUT IN TABULAR FORMAT +(///T14,'MODE',T24,'COEFF',T34,'ISYM',/)""" + + pycmd = """with mapdl.non_interactive: + mapdl.run("*VWRITE") # WRITE OUTPUT IN TABULAR FORMAT + mapdl.run("(///T14,'MODE',T24,'COEFF',T34,'ISYM',/)")""" + + assert pycmd in convert_apdl_block(cmd, only_commands=True) From be71fb53f6572e17bbfa49068ed5e33d2d7abfe4 Mon Sep 17 00:00:00 2001 From: German Date: Tue, 24 Oct 2023 17:26:07 +0200 Subject: [PATCH 69/70] Fixing kabs vs kswp in Xsel commands --- src/ansys/mapdl/core/misc.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ansys/mapdl/core/misc.py b/src/ansys/mapdl/core/misc.py index 4b526712e7..29aa153e7f 100644 --- a/src/ansys/mapdl/core/misc.py +++ b/src/ansys/mapdl/core/misc.py @@ -1249,13 +1249,13 @@ def wrapper(self, *args, **kwargs): else: return original_sel_func( self, - type_=type_, - item=item, - comp=comp, - vmin=vmin, - vmax=vmax, - vinc=vinc, - kabs=kabs, + type_, + item, + comp, + vmin, + vmax, + vinc, + kabs, # ksel, esel, nsel uses kabs, but lsel, asel, vsel uses kswp **kwargs, ) From c748d0de15c156e60b559d6a5aa67ef2445490f9 Mon Sep 17 00:00:00 2001 From: German Date: Tue, 24 Oct 2023 17:39:05 +0200 Subject: [PATCH 70/70] Fixing not plotting when no show command was set. IMGREAD issue. --- src/ansys/mapdl/core/mapdl.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ansys/mapdl/core/mapdl.py b/src/ansys/mapdl/core/mapdl.py index d34a012a44..891843f1c2 100644 --- a/src/ansys/mapdl/core/mapdl.py +++ b/src/ansys/mapdl/core/mapdl.py @@ -3307,8 +3307,17 @@ def run( # Edge case. `\title, 'par=1234' ` self._check_parameter_name(param_name) + short_cmd = parse_to_short_cmd(command) text = self._run(command, verbose=verbose, mute=mute) + if ( + "Display device has not yet been specified with the /SHOW command" in text + and short_cmd in PLOT_COMMANDS + ): + # Reissuing the command to make sure we get output. + self.show(self.default_file_type_for_plots) + text = self._run(command, verbose=verbose, mute=mute) + if command[:4].upper() == "/CLE" and self.is_grpc: # We have reset the database, so we need to create a new session id self._create_session() @@ -3328,8 +3337,6 @@ def run( self._raise_errors(text) # special returns for certain geometry commands - short_cmd = parse_to_short_cmd(command) - if short_cmd in PLOT_COMMANDS: self._log.debug("It is a plot command.") plot_path = self._get_plot_name(text)