Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Math module file uploader #944

Merged
merged 20 commits into from
Mar 9, 2022
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
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ Next, connect to the instance of MAPDL from python with:

>>> from ansys.mapdl.core import Mapdl
>>> ip = '127.0.0.1'
>>> mapdl = Mapdl(ip=ip, port=50052, request_instance=False)
>>> mapdl = Mapdl(ip=ip, port=50052, start_instance=False)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't me, it was @koubaa who told me. It seems that parameter is quite common in some private repositories I'm not in.

>>> print(mapdl)


Expand Down
4 changes: 3 additions & 1 deletion src/ansys/mapdl/core/mapdl_grpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1866,7 +1866,9 @@ def _mat_data(self, pname, raw=False):
if raw: # for debug
return vals, indices, indptr, shape
else:
return sparse.csr_matrix((vals, indices, indptr), shape=shape)
return sparse.csr_matrix(
(vals, indices, indptr), dtype=stype, shape=shape
)

raise ValueError(f'Invalid matrix type "{mtype}"')

Expand Down
125 changes: 114 additions & 11 deletions src/ansys/mapdl/core/math.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,8 +418,9 @@ def load_matrix_from_file(
Parameters
----------
dtype : numpy.dtype, optional
Numpy data type to store the vector as. Defaults to
``np.double``.
Numpy data type to store the vector as. You can use double ("DOUBLE" or "D"),
or complex numbers ("COMPLEX" or "Z"). Alternatively you can also supply a
numpy data type. Defaults to ``np.double``.
fname : str, optional
Filename to read the matrix from. Defaults to ``"file.full"``.
mat_id : str, optional
Expand Down Expand Up @@ -450,21 +451,100 @@ def load_matrix_from_file(
self._mapdl._log.info(
"Calling MAPDL to extract the %s matrix from %s", mat_id, fname
)
quotes = "'"
allowed_mat_id = (
"STIFF",
"MASS",
"DAMP",
"NOD2BCS",
"USR2BCS",
"GMAT",
"K_RE",
"K_IM",
)
if mat_id.upper() not in allowed_mat_id:
raise ValueError(
f"The 'mat_id' parameter supplied ('{mat_id}') is not allowed. "
f"Only the following are allowed: \n{', '.join([quotes + each + quotes for each in allowed_mat_id])}"
)

if isinstance(dtype, str):
if dtype.lower() not in ("complex", "double", "d", "z"):
raise ValueError(
f"Data type ({dtype}) not allowed as a string."
"Use either: 'double' or 'complex', or a valid numpy data type."
)
if dtype.lower() in ("complex", "z"):
dtype_ = "'Z'"
dtype = np.complex64
else:
dtype_ = "'D'"
dtype = np.double
else:
if dtype not in ANSYS_VALUE_TYPE.values():
allowables_np_dtypes = ", ".join(
[
str(each).split("'")[1]
for each in ANSYS_VALUE_TYPE.values()
if each
]
)
raise ValueError(
f"Numpy data type not allowed. Only: {allowables_np_dtypes}"
)
if "complex" in str(dtype):
dtype_ = "'Z'"
else:
dtype_ = "'D'"

if dtype_ == "'Z'" and mat_id.upper() in ("STIFF", "MASS", "DAMP"):
raise ValueError(
"Reading the stiffness, mass or damping matrices to a complex array is not supported."
)

self._mapdl.run(
f"*SMAT,{name},{MYCTYPE[dtype]},IMPORT,FULL,{fname},{mat_id}", mute=True
f"*SMAT,{name},{dtype_},IMPORT,FULL,{fname},{mat_id}", mute=True
)
ans_sparse_mat = AnsSparseMat(name, self._mapdl)
if asarray:
return self._mapdl._mat_data(ans_sparse_mat.id)
return self._mapdl._mat_data(ans_sparse_mat.id).astype(dtype)
return ans_sparse_mat

def _load_file(self, fname):
"""
Provide file to MAPDL instance.

If in local:
Checks if the file exists, if not, it raises a FileNotFound exception

If in not-local:
Check if the file exists locally or in the working directory, if not, it will raise a FileNotFound exception.
If the file is local, it will be uploaded.

"""
if self._mapdl._local: # pragma: no cover
if not os.path.exists(fname):
raise FileNotFoundError(f"The file {fname} could not be found.")
else:
if not os.path.exists(fname) and fname not in self._mapdl.list_files():
raise FileNotFoundError(
f"The file {fname} could not be found in the local client or remote working directory."
)
if os.path.exists(fname):
self._mapdl.upload(fname)
fname = os.path.basename(fname)

return fname

def stiff(self, dtype=np.double, fname="file.full", asarray=False):
"""Load the stiffness matrix from a full file.

Parameters
----------
dtype : numpy.dtype, optional
Numpy data type to store the vector as. Defaults to ``np.double``
Numpy data type to store the vector as. Only applicable if
``asarray=True``, otherwise the returned matrix contains
double float numbers. Defaults to ``np.double``
fname : str, optional
Filename to read the matrix from.
asarray : bool, optional
Expand All @@ -488,6 +568,7 @@ def stiff(self, dtype=np.double, fname="file.full", asarray=False):
<60x60 sparse matrix of type '<class 'numpy.float64'>'
with 1734 stored elements in Compressed Sparse Row format>
"""
fname = self._load_file(fname)
return self.load_matrix_from_file(dtype, fname, "STIFF", asarray)

def mass(self, dtype=np.double, fname="file.full", asarray=False):
Expand All @@ -496,8 +577,9 @@ def mass(self, dtype=np.double, fname="file.full", asarray=False):
Parameters
----------
dtype : numpy.dtype, optional
Numpy data type to store the vector as. Defaults to
``np.double``.
Numpy data type to store the vector as. Only applicable if
``asarray=True``, otherwise the returned matrix contains
double float numbers. Defaults to ``np.double``
fname : str, optional
Filename to read the matrix from.
asarray : bool, optional
Expand All @@ -522,6 +604,7 @@ def mass(self, dtype=np.double, fname="file.full", asarray=False):
<60x60 sparse matrix of type '<class 'numpy.float64'>'
with 1734 stored elements in Compressed Sparse Row format>
"""
fname = self._load_file(fname)
return self.load_matrix_from_file(dtype, fname, "MASS", asarray)

def damp(self, dtype=np.double, fname="file.full", asarray=False):
Expand All @@ -530,8 +613,9 @@ def damp(self, dtype=np.double, fname="file.full", asarray=False):
Parameters
----------
dtype : numpy.dtype, optional
Numpy data type to store the vector as. Defaults to
``np.double``.
Numpy data type to store the vector as. Only applicable if
``asarray=True``, otherwise the returned matrix contains
double float numbers. Defaults to ``np.double``
fname : str, optional
Filename to read the matrix from.
asarray : bool, optional
Expand All @@ -557,6 +641,7 @@ def damp(self, dtype=np.double, fname="file.full", asarray=False):
with 1734 stored elements in Compressed Sparse Row format>

"""
fname = self._load_file(fname)
return self.load_matrix_from_file(dtype, fname, "DAMP", asarray)

def get_vec(self, dtype=np.double, fname="file.full", mat_id="RHS", asarray=False):
Expand Down Expand Up @@ -596,6 +681,8 @@ def get_vec(self, dtype=np.double, fname="file.full", mat_id="RHS", asarray=Fals
self._mapdl._log.info(
"Call MAPDL to extract the %s vector from the file %s", mat_id, fname
)

fname = self._load_file(fname)
self._mapdl.run(
f"*VEC,{name},{MYCTYPE[dtype]},IMPORT,FULL,{fname},{mat_id}", mute=True
)
Expand Down Expand Up @@ -658,6 +745,7 @@ def rhs(self, dtype=np.double, fname="file.full", asarray=False):
APDLMath Vector Size 126

"""
fname = self._load_file(fname)
return self.get_vec(dtype, fname, "RHS", asarray)

def svd(self, mat, thresh="", sig="", v="", **kwargs):
Expand Down Expand Up @@ -1338,9 +1426,19 @@ def sym(self): # BUG this is not always true
"""Return if matrix is symmetric."""
return True

def asarray(self) -> np.ndarray:
def asarray(self, dtype=None) -> np.ndarray:
"""Returns vector as a numpy array.

Parameters
----------
dtype : numpy.dtype, optional
Numpy data type

Returns
-------
np.ndarray
Numpy array with the defined data type

Examples
--------
>>> from ansys.mapdl.core import launch_mapdl
Expand All @@ -1349,9 +1447,14 @@ def asarray(self) -> np.ndarray:
>>> v = mm.ones(10)
>>> v.asarray()
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
>>> v.asarray(dtype=np.int)
[1 1 1 1 1 1 1 1 1 1]

"""
return self._mapdl._mat_data(self.id)
if dtype:
return self._mapdl._mat_data(self.id).astype(dtype)
else:
return self._mapdl._mat_data(self.id)

def __mul__(self, vec):
raise AttributeError(
Expand Down
97 changes: 96 additions & 1 deletion tests/test_math.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Test APDL Math functionality"""
import os
import re
from shutil import copy

import numpy as np
import pytest
Expand Down Expand Up @@ -180,12 +182,101 @@ def test_getitem(mm):
assert vec[j] == np_mat[j, i]


def test_load_stiff_mass(mm, cube_solve):
def test_load_stiff_mass(mm, cube_solve, tmpdir):
k = mm.stiff()
m = mm.mass()
assert k.shape == m.shape


def test_load_stiff_mass_different_location(mm, cube_solve, tmpdir):
full_files = mm._mapdl.download("*.full")
assert os.path.exists(full_files[0])
full_path = os.path.join(os.getcwd(), full_files[0])
copy(full_path, tmpdir)
fname_ = os.path.join(tmpdir, full_files[0])
assert os.path.exists(fname_)

k = mm.stiff(fname=fname_)
m = mm.mass(fname=fname_)
assert k.shape == m.shape
assert all([each > 0 for each in k.shape])
assert all([each > 0 for each in m.shape])


def test_load_stiff_mass_as_array(mm, cube_solve):
k = mm.stiff(asarray=True)
m = mm.mass(asarray=True)

assert sparse.issparse(k)
assert sparse.issparse(m)
assert all([each > 0 for each in k.shape])
assert all([each > 0 for each in m.shape])


def test_stiff_mass_as_array(mm, cube_solve):
k = mm.stiff()
m = mm.mass()

k = k.asarray()
m = m.asarray()

assert sparse.issparse(k)
assert sparse.issparse(m)
assert all([each > 0 for each in k.shape])
assert all([each > 0 for each in m.shape])


@pytest.mark.parametrize(
"dtype_",
[
np.int64,
np.double,
pytest.param(np.complex64, marks=pytest.mark.xfail),
pytest.param("Z", marks=pytest.mark.xfail),
"D",
pytest.param("dummy", marks=pytest.mark.xfail),
pytest.param(np.int8, marks=pytest.mark.xfail),
],
)
def test_load_stiff_mass_different_dtype(mm, cube_solve, dtype_):
# AnsMat object do not support dtype assignment, you need to convert them to array first.
k = mm.stiff(asarray=True, dtype=dtype_)
m = mm.mass(asarray=True, dtype=dtype_)

if isinstance(dtype_, str):
if dtype_ == "Z":
dtype_ = np.complex_
else:
dtype_ = np.double

assert sparse.issparse(k)
assert sparse.issparse(m)
assert all([each > 0 for each in k.shape])
assert all([each > 0 for each in m.shape])
assert k.dtype == dtype_
assert m.dtype == dtype_

k = mm.stiff(dtype=dtype_)
m = mm.mass(dtype=dtype_)

k = k.asarray(dtype=dtype_)
m = m.asarray(dtype=dtype_)

assert sparse.issparse(k)
assert sparse.issparse(m)
assert all([each > 0 for each in k.shape])
assert all([each > 0 for each in m.shape])
assert k.dtype == dtype_
assert m.dtype == dtype_


def test_load_matrix_from_file_incorrect_mat_id(mm, cube_solve):
with pytest.raises(
ValueError, match=r"The 'mat_id' parameter supplied.*is not allowed."
):
mm.load_matrix_from_file(fname="file.full", mat_id="DUMMY")


def test_mat_from_name(mm):
mat0 = mm.mat(10, 10)
mat1 = mm.mat(name=mat0.id)
Expand Down Expand Up @@ -429,3 +520,7 @@ def test_free(mm):

def test_repr(mm):
assert mm._status == repr(mm)


def test_status(mm):
mm.status()
germa89 marked this conversation as resolved.
Show resolved Hide resolved