Skip to content

Commit 89ba3dd

Browse files
FredAnsakaszynski
andauthored
Fred ans/update tests (#338)
* Mew MapdlVsScipy test * Fix syntax * Fix path to wing.dat model * add wing.dat to the setup.py file * comment out the automatically generated get_ipython calls * remove the mapdl.exit call * Add a Graph to the eigen_solve example * Fix import matplotlib * pep8 changes; clean up desc * additional flow cleanup * version bump to 0.57.3 Co-authored-by: Alex Kaszynski <[email protected]>
1 parent dbf125d commit 89ba3dd

File tree

7 files changed

+412
-6
lines changed

7 files changed

+412
-6
lines changed

ansys/mapdl/core/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Version of ansys-mapdl-core module."""
22

33
# major, minor, patch
4-
version_info = 0, 57, 2
4+
version_info = 0, 57, 3
55

66
# Nice string for the version
77
__version__ = '.'.join(map(str, version_info))

ansys/mapdl/core/examples/examples.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,11 @@
33

44
# get location of this folder and the example files
55
dir_path = os.path.dirname(os.path.realpath(__file__))
6+
7+
# add any files you'd like to import here. For example:
8+
wing_model = os.path.join(dir_path, 'wing.dat')
9+
10+
# be sure to add the input file directly in this directory
11+
# This way, files can be loaded with:
12+
# from ansys.mapdl.core import examples
13+
# examples.wing_model

ansys/mapdl/core/examples/wing.dat

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/batch
2+
/nopr
3+
4+
!!! need to input dofs and eqnslvr
5+
!!! /debug,stat
6+
7+
dofs = 100
8+
eltype = 186
9+
10+
11+
! define parameters
12+
aspect=1.0
13+
level=1
14+
dof_nd=3
15+
ndofs=dofs*100
16+
17+
*if,ndofs,lt,1001,then
18+
a_size=.5
19+
*elseif,ndofs,lt,50001,then
20+
a_size=.1
21+
*elseif,ndofs,lt,100001,then
22+
a_size=.075
23+
*elseif,ndofs,lt,350001,then
24+
a_size=.050
25+
*elseif,ndofs,lt,2000001,then
26+
a_size=.030
27+
*elseif,ndofs,lt,7500001,then
28+
a_size=.015
29+
*else
30+
a_size=.010
31+
*endif
32+
33+
/PREP7
34+
shpp,off
35+
ET,1,PLANE42 ! Define PLANE42 as element type 1
36+
ET,2,eltype ! Define SOLID186 as element type 2
37+
*if,eltype,eq,186,then
38+
KEYOPT,2,1,0
39+
*endif
40+
MP,EX,1,38000
41+
MP,DENS,1,1.033E-3
42+
MP,NUXY,1,.3
43+
K,1 ! Define keypoint 1 at 0,0,0
44+
K,2,2 ! Define keypoint 2 at 2,0,0
45+
K,3,2.3,.2 ! Define keypoint 3 at 2.3,.2,0
46+
K,4,1.9,.45 ! Define keypoint 4 at 1.9,.45,0
47+
K,5,1,.25 ! Define keypoint 5 at 1,.25,0
48+
LSTR,1,2 ! Create a straight line between keypoints 1 and 2
49+
LSTR,5,1 ! Create a straight line between keypoints 5 and 1
50+
BSPLIN,2,3,4,5,,,-1,,,-1,-.25 ! Create a B-spline
51+
AL,1,3,2
52+
ESIZE,a_size
53+
AMESH,1
54+
55+
*get,a_nodes,node,,count
56+
*if,eltype,eq,186,then
57+
zdiv=ndofs/(11*a_nodes) - 1
58+
*else
59+
zdiv=ndofs/(3*a_nodes) - 1
60+
*endif
61+
zlth=a_size*zdiv*aspect
62+
zdiv=nint(zdiv)
63+
esiz,,zdiv
64+
*if,zlth,le,0,then
65+
zlth=1
66+
*endif
67+
68+
TYPE,2
69+
VEXT,ALL,,,,,zlth
70+
modmsh,detach
71+
emid,add,all
72+
allsel,all
73+
74+
FINI

examples/01-apdlmath-examples/eigen_solve.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
your own sparse or dense matrices and solve those.
1010
1111
"""
12+
import matplotlib.pylab as plt
1213
import time
1314
import numpy as np
1415

@@ -58,7 +59,6 @@
5859

5960
###############################################################################
6061
# This is the vector of eigenfrequencies.
61-
#
6262
print(ev)
6363

6464
###############################################################################
@@ -79,7 +79,6 @@
7979
###############################################################################
8080
# Then we get the 1st Eigenshape :math:`\phi_1`, and compute
8181
# :math:`K.\phi_1` and :math:`M.\phi_1`
82-
#
8382

8483
# shape
8584
phi = a[0]
@@ -151,7 +150,22 @@ def get_res(i):
151150
return kphi.norm()/kphinrm
152151

153152

153+
mapdl_acc = np.zeros(nev)
154+
154155
for i in range(nev):
155156
f = ev[i]
156-
res = get_res(i)
157-
print(f'[{i}] : Freq = {f}\t - Residual = {res}')
157+
mapdl_acc[i] = get_res(i)
158+
print(f'[{i}] : Freq = {f}\t - Residual = {mapdl_acc[i]}')
159+
160+
###############################################################################
161+
# Plot Accuracy of Eigenresults
162+
163+
fig = plt.figure(figsize=(12, 10))
164+
ax = plt.axes()
165+
x = np.linspace(1, nev, nev)
166+
plt.title('APDL Math Residual Error (%)')
167+
plt.yscale('log')
168+
plt.ylim([10E-13, 10E-7])
169+
plt.xlabel('Frequency #')
170+
plt.ylabel('Errors (%)')
171+
ax.bar(x, mapdl_acc, label='MAPDL Results')
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
"""
2+
.. _ref_mapdl_math_mapdl_vs_scipy:
3+
4+
Compute Eigenvalues using MAPDL or SciPy
5+
----------------------------------------
6+
7+
This example shows:
8+
9+
- How to extract the stiffness and mass matrices from a MAPDL model.
10+
- How to use the ``Math`` module of PyMapdl to compute the first
11+
eigenvalues.
12+
- How to can get these matrices in the SciPy world, to get the same
13+
solutions using Python resources.
14+
- How MAPDL is really faster than SciPy :)
15+
"""
16+
17+
###############################################################################
18+
# First load python packages we need for this example
19+
import time
20+
import math
21+
22+
import matplotlib.pylab as plt
23+
import numpy as np
24+
import scipy
25+
from scipy.sparse.linalg import eigsh
26+
27+
from ansys.mapdl.core import launch_mapdl
28+
from ansys.mapdl.core import examples
29+
30+
###############################################################################
31+
# Next:
32+
#
33+
# - Load the ansys.mapdl module
34+
# - Get the ``Math`` module of PyMapdl
35+
#
36+
mapdl = launch_mapdl()
37+
print(mapdl)
38+
mm = mapdl.math
39+
40+
###############################################################################
41+
# APDLMath EigenSolve
42+
# First load the input file using MAPDL.
43+
#
44+
print(mapdl.input(examples.examples.wing_model))
45+
46+
47+
###############################################################################
48+
# Plot and mesh using the ``eplot`` method.
49+
mapdl.eplot()
50+
51+
52+
###############################################################################
53+
# Next, setup a modal Analysis and request the :math:`K` and math:`M`
54+
# matrices to be formed. MAPDL stores these matrices in a ``.FULL``
55+
# file.
56+
57+
print(mapdl.slashsolu())
58+
print(mapdl.antype(antype='MODAL'))
59+
print(mapdl.modopt(method='LANB', nmode='10', freqb='1.'))
60+
print(mapdl.wrfull(ldstep='1'))
61+
62+
# store the output of the solve command
63+
output = mapdl.solve()
64+
65+
66+
###############################################################################
67+
# Read the sparse matrices using PyMapdl.
68+
#
69+
mapdl.finish()
70+
mm.free()
71+
k = mm.stiff(fname='file.full')
72+
M = mm.mass(fname='file.full')
73+
74+
75+
###############################################################################
76+
# Solve the eigenproblem using PyMapdl with APDLMath.
77+
#
78+
nev = 10
79+
A = mm.mat(k.nrow, nev)
80+
81+
t1 = time.time()
82+
ev = mm.eigs(nev, k, M, phi=A, fmin=1.)
83+
t2 = time.time()
84+
mapdl_elapsed_time = t2-t1
85+
print('\nElapsed time to solve this problem : ', mapdl_elapsed_time)
86+
87+
###############################################################################
88+
# Print eigenfrequencies and accuracy.
89+
#
90+
# Accuracy : :math:`\frac{||(K-\lambda.M).\phi||_2}{||K.\phi||_2}`
91+
#
92+
mapdl_acc = np.empty(nev)
93+
94+
for i in range(nev):
95+
f = ev[i] # Eigenfrequency (Hz)
96+
omega = 2*np.pi*f # omega = 2.pi.Frequency
97+
lam = omega**2 # lambda = omega^2
98+
99+
phi = A[i] # i-th eigenshape
100+
kphi = k.dot(phi) # K.Phi
101+
mphi = M.dot(phi) # M.Phi
102+
103+
kphi_nrm = kphi.norm() # Normalization scalar value
104+
105+
mphi *= lam # (K-\lambda.M).Phi
106+
kphi -= mphi
107+
108+
mapdl_acc[i] = kphi.norm()/kphi_nrm # compute the residual
109+
print(f"[{i}] : Freq = {f:8.2f} Hz\t Residual = {mapdl_acc[i]:.5}")
110+
111+
112+
###############################################################################
113+
# Use SciPy to Solve the same Eigenproblem
114+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
115+
#
116+
# First get MAPDL sparse matrices into the Python memory as SciPy
117+
# matrices.
118+
#
119+
pk = k.asarray()
120+
pm = M.asarray()
121+
122+
# get_ipython().run_line_magic('matplotlib', 'inline')
123+
124+
fig, (ax1, ax2) = plt.subplots(1, 2)
125+
fig.suptitle('K and M Matrix profiles')
126+
ax1.spy(pk, markersize=0.01)
127+
ax1.set_title('K Matrix')
128+
ax2.spy(pm, markersize=0.01)
129+
ax2.set_title('M Matrix')
130+
plt.show(block=True)
131+
132+
133+
###############################################################################
134+
# Make the sparse matrices for SciPy unsymmetric as symmetric matrices in SciPy
135+
# are memory inefficient.
136+
#
137+
# :math:`K = K + K^T - diag(K)`
138+
#
139+
pkd = scipy.sparse.diags(pk.diagonal())
140+
pK = pk + pk.transpose() - pkd
141+
pmd = scipy.sparse.diags(pm.diagonal())
142+
pm = pm + pm.transpose() - pmd
143+
144+
145+
###############################################################################
146+
# Plot Matrices
147+
#
148+
fig, (ax1, ax2) = plt.subplots(1, 2)
149+
fig.suptitle('K and M Matrix profiles')
150+
ax1.spy(pk, markersize=0.01)
151+
ax1.set_title('K Matrix')
152+
ax2.spy(pm, markersize=0.01)
153+
ax2.set_title('M Matrix')
154+
plt.show(block=True)
155+
156+
157+
###############################################################################
158+
# Solve the eigenproblem
159+
#
160+
t3 = time.time()
161+
vals, vecs = eigsh(A=pK, M=pm, k=10, sigma=1, which='LA')
162+
t4 = time.time()
163+
scipy_elapsed_time = t4 - t3
164+
print('\nElapsed time to solve this problem : ', scipy_elapsed_time)
165+
166+
167+
###############################################################################
168+
# Convert Lambda values to Frequency values:
169+
# :math:`freq = \frac{\sqrt(\lambda)}{2.\pi}`
170+
#
171+
freqs = np.sqrt(vals) / (2*math.pi)
172+
173+
174+
###############################################################################
175+
# Compute the residual error for SciPy.
176+
#
177+
# :math:`Err=\frac{||(K-\lambda.M).\phi||_2}{||K.\phi||_2}`
178+
#
179+
scipy_acc = np.zeros(nev)
180+
181+
for i in range(nev):
182+
lam = vals[i] # i-th eigenvalue
183+
phi = vecs.T[i] # i-th eigenshape
184+
185+
kphi = pk*phi.T # K.Phi
186+
mphi = pm*phi.T # M.Phi
187+
188+
kphi_nrm = np.linalg.norm(kphi, 2) # Normalization scalar value
189+
190+
mphi *= lam # (K-\lambda.M).Phi
191+
kphi -= mphi
192+
193+
scipy_acc[i] = 1 - np.linalg.norm(kphi, 2)/kphi_nrm # compute the residual
194+
print(f"[{i}] : Freq = {freqs[i]:8.2f} Hz\t Residual = {scipy_acc[i]:.5}")
195+
196+
197+
###############################################################################
198+
# MAPDL is more accurate than SciPy.
199+
#
200+
fig = plt.figure(figsize=(12, 10))
201+
ax = plt.axes()
202+
x = np.linspace(1, 10, 10)
203+
plt.title('Residual Error')
204+
plt.yscale('log')
205+
plt.xlabel('Mode')
206+
plt.ylabel('% Error')
207+
ax.bar(x, scipy_acc, label='SciPy Results')
208+
ax.bar(x, mapdl_acc, label='MAPDL Results')
209+
plt.legend(loc='lower right')
210+
plt.show()
211+
212+
###############################################################################
213+
# MAPDL is faster than SciPy.
214+
#
215+
ratio = scipy_elapsed_time/mapdl_elapsed_time
216+
print(f"Mapdl is {ratio:.3} times faster")

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@
5656

5757
python_requires='>=3.6.*',
5858
keywords='ANSYS MAPDL gRPC',
59-
package_data={'ansys.mapdl.core.examples': ['verif/*.dat']},
59+
package_data={'ansys.mapdl.core.examples': ['verif/*.dat',
60+
'wing.dat']},
6061

6162
install_requires=install_requires,
6263
)

0 commit comments

Comments
 (0)