Skip to content

fix: update mpwrite and mpread methods to enforce 'LIB' as the only valid lib argument #4123

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Aug 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/changelog.d/4123.miscellaneous.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix: update mpwrite and mpread methods to enforce 'lib' as the only valid lib argument
88 changes: 66 additions & 22 deletions src/ansys/mapdl/core/mapdl_extended.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
allow_iterables_vmin,
allow_pickable_entities,
check_deprecated_vtk_kwargs,
load_file,
random_string,
requires_graphics,
supress_logging,
Expand Down Expand Up @@ -345,7 +344,7 @@ def mpwrite(
self,
fname="",
ext="",
lib="",
lib="LIB",
mat="",
download_file=False,
progress_bar=False,
Expand All @@ -359,23 +358,81 @@ def mpwrite(
f"The supplied path {fname_} is not allowed."
)

output = super().mpwrite(fname, ext, lib, mat, **kwargs)
output = super().mpwrite(fname, ext, lib=lib, mat=mat, **kwargs)
if download_file:
self.download(os.path.basename(fname_), progress_bar=progress_bar)

return output

@wraps(_MapdlCore.mpread)
def mpread(self, fname="", ext="", lib="", **kwargs):
"""APDL Command: MPREAD

Reads a file containing material properties.

Parameters
----------
fname
File name and directory path (248 characters maximum,
including directory). If you do not specify the ``LIB``
option, the default directory is the current working
directory. If you specify the ``LIB`` option, the default is
the following search path: the current working directory,
the user's home directory, ``MPLIB_DIR`` (as specified by the
``/MPLIB,READ,PATH`` command) and ``/ansys_dir/matlib`` (as
defined by installation). If you use the default for your
directory, you can use all 248 characters for the file
name.

ext
Filename extension (eight-character maximum).

lib
Reads material library files previously written with the
MPWRITE command. (See the description of the ``LIB`` option
for the ``MPWRITE`` command.) The only allowed value for ``LIB``
is ``LIB``.

.. note:: The argument "LIB" is not supported by the MAPDL gRPC server.

Notes
-----
Material properties written to a file without the ``LIB`` option
do not support nonlinear properties. Also, properties written
to a file without the ``LIB`` option are restored in the same
material number as originally defined. To avoid errors, use
``MPREAD`` with the ``LIB`` option only when reading files written
using MPWRITE with the ``LIB`` option.

If you omit the ``LIB`` option for ``MPREAD``, this command supports
only linear properties.

Material numbers are hardcoded. If you write a material file
without specifying the ``LIB`` option, then read that file in
using the ``MPREAD`` command with the ``LIB`` option, the ANSYS
program will not write the file to a new material number.
Instead, it will write the file to the "old" material number
(the number specified on the MPWRITE command that created the
file.)

This command is also valid in SOLUTION.
"""
if lib:
raise NotImplementedError(
"The option 'lib' is not supported by the MAPDL gRPC server."
"The 'lib' argument is not supported by the MAPDL gRPC server."
)

fname_ = fname + "." + ext
fname = load_file(self, fname_)
self._log.info("Bypassing 'MPREAD' with 'INPUT'.")
return self.input(fname)
fname = self._get_file_name(fname, ext, "mp")
fname = self._get_file_path(fname, kwargs.get("progress_bar", False))
file_, ext_, path_ = self._decompose_fname(fname)
with self.non_interactive:
# Use not interactive to avoid gRPC issues. See #975
if self._local:
# If local, we can use the full path
super().mpread(fname=path_ / file_, ext=ext_, lib=lib, **kwargs)
else:
super().mpread(fname=file_, ext=ext_, lib=lib, **kwargs)

return self.last_response

@wraps(_MapdlCore.cwd)
def cwd(self, *args, **kwargs):
Expand All @@ -390,19 +447,6 @@ def cwd(self, *args, **kwargs):

@wraps(_MapdlCore.list)
def list(self, filename, ext=""):
"""Displays the contents of an external, coded file.

APDL Command: ``/LIST``

Parameters
----------
fname : str
File name and directory path. An unspecified directory
path defaults to the working directory.

ext : str, optional
Filename extension
"""
if hasattr(self, "_local"): # gRPC
if not self._local:
return self._download_as_raw(filename).decode()
Expand Down
2 changes: 2 additions & 0 deletions tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,8 @@ class Test_MAPDL_commands(TestClass):
"lgwrite",
"lplot",
"lsread",
"mpread",
"mpwrite",
"mwrite",
"nplot",
"sys",
Expand Down
71 changes: 51 additions & 20 deletions tests/test_mapdl.py
Original file line number Diff line number Diff line change
Expand Up @@ -1492,33 +1492,37 @@ def test_mpfunctions(mapdl, cube_solve, capsys):
ext = "mp1"

mapdl.prep7()
mapdl.slashdelete(fname, ext) # remove file if it exists

assert f"WRITE OUT MATERIAL PROPERTY LIBRARY TO FILE=" in mapdl.mpwrite(fname, ext)
assert "WRITE OUT MATERIAL PROPERTY" in mapdl.mpwrite(fname, ext, mat=1)
assert f"{fname}.{ext}" in mapdl.list_files()

# asserting downloading
ext = "mp2"
assert f"WRITE OUT MATERIAL PROPERTY LIBRARY TO FILE=" in mapdl.mpwrite(
fname, ext, download_file=True
mapdl.slashdelete(fname, ext) # remove file if it exists

assert "WRITE OUT MATERIAL PROPERTY" in mapdl.mpwrite(
fname, ext, download_file=True, mat=1
)
assert f"{fname}.{ext}" in mapdl.list_files()
assert os.path.exists(f"{fname}.{ext}")

## Checking reading
# Uploading a local file
with open(f"{fname}.{ext}", "r") as fid:
text = fid.read()
content = fid.read()

os.remove(f"{fname}.{ext}") # remove temp file

ext = ext + "2"
mapdl.slashdelete(fname, ext) # remove file if it exists

fname_ = f"{fname}.{ext}"
new_nuxy = "MPDATA,NUXY, 1, 1, 0.4000000E+00,"
nuxy = float(new_nuxy.split(",")[4])
nuxy = float(0.40000)
ex = 0.2100000e12

with open(fname_, "w") as fid:
fid.write(text.replace("MPDATA,NUXY, 1, 1, 0.3000000E+00,", new_nuxy))
fid.write(content.replace("0.30000", str(nuxy)))

# file might be left behind from a previous test
if fname_ in mapdl.list_files():
Expand All @@ -1527,17 +1531,10 @@ def test_mpfunctions(mapdl, cube_solve, capsys):

mapdl.clear()
mapdl.prep7()
captured = capsys.readouterr() # To flush it
output = mapdl.mpread(fname, ext)
_ = capsys.readouterr() # To flush it
output = mapdl.mpread(fname, ext, progress_bar=True)
captured = capsys.readouterr()
if has_dependency("tqdm"):
# Printing uploading requires tqdm
assert f"Uploading {fname}.{ext}:" in captured.err

assert "PROPERTY TEMPERATURE TABLE NUM. TEMPS= 1" in output
assert "TEMPERATURE TABLE ERASED." in output
assert "0.4000000" in output
# check if materials are read into the db

assert mapdl.get_value("NUXY", "1", "TEMP", 0) == nuxy
assert np.allclose(mapdl.get_value("EX", 1, "TEMP", 0), ex)

Expand All @@ -1551,9 +1548,6 @@ def test_mpfunctions(mapdl, cube_solve, capsys):
mapdl.clear()
mapdl.prep7()
output = mapdl.mpread(fname, ext)
assert "PROPERTY TEMPERATURE TABLE NUM. TEMPS= 1" in output
assert "TEMPERATURE TABLE ERASED." in output
assert "0.4000000" in output
assert np.allclose(mapdl.get_value("NUXY", "1", "TEMP", 0), nuxy)
assert np.allclose(mapdl.get_value("EX", 1, "TEMP", 0), ex)

Expand All @@ -1570,6 +1564,43 @@ def test_mpfunctions(mapdl, cube_solve, capsys):
with pytest.raises(IOError):
mapdl.mpwrite("/test_dir/test", "mp")

mapdl.slashdelete(fname, ext) # remove file if it exists


def test_mpread_lib(mapdl):
mapdl.input_strings(
"""
/prep7
/units,si
TB,BH ,_MATL , 1, 20
TBTEM, 0.00000000 , 1
TBPT,, 59.5238095 , 0.200000000
TBPT,, 119.047619 , 0.400000000
TBPT,, 158.730159 , 0.550000000
TBPT,, 396.825397 , 1.15000000
TBPT,, 555.555556 , 1.30000000
TBPT,, 793.650794 , 1.40000000
TBPT,, 1587.30159 , 1.55000000
TBPT,, 3968.25397 , 1.63500000
TBPT,, 7936.50794 , 1.65500000
TBPT,, 15873.0159 , 1.67500000
TBPT,, 31746.0317 , 1.70138960
TBPT,, 63492.0635 , 1.75000000
TBPT,, 95238.0952 , 1.79000000
TBPT,, 190476.190 , 1.90980000
TBPT,, 285714.286 , 2.02960000
TBPT,, 380952.381 , 2.14950000
"""
)
mapdl.slashdelete("database", "mp")
mapdl.mpwrite("database", "mp", mat=1)

mapdl.clear()
mapdl.prep7()
mapdl.mpread("database", "mp")
mapdl.mplist()
assert mapdl.get_value("MAT", 0, "count") == 1.0


def test_mapdl_str(mapdl, cleared):
out = str(mapdl)
Expand Down
Loading