Skip to content

Commit 13f709f

Browse files
committed
updated readme
1 parent 8438faa commit 13f709f

File tree

5 files changed

+195
-91
lines changed

5 files changed

+195
-91
lines changed

doc/examples.rst

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -129,49 +129,6 @@ Here's the same result as viewed from ANSYS.
129129
.. image:: ansys_stress.png
130130

131131

132-
Reading a Full File
133-
-------------------
134-
This example reads in the mass and stiffness matrices associated with the above
135-
example.
136-
137-
.. code:: python
138-
139-
# Load the reader from pyansys
140-
import pyansys
141-
142-
# Create result reader object and read in full file
143-
fobj = pyansys.FullReader('file.full')
144-
fobj.LoadFullKM()
145-
146-
147-
Data from the full file can now be accessed from the object. If you have
148-
``scipy`` installed, you can construct a sparse matrix and solve it.
149-
150-
.. code:: python
151-
152-
import numpy as np
153-
from scipy.sparse import csc_matrix, linalg
154-
ndim = fobj.nref.size
155-
k = csc_matrix((fobj.kdata, (fobj.krows, fobj.kcols)), shape=(ndim, ndim))
156-
m = csc_matrix((fobj.mdata, (fobj.mrows, fobj.mcols)), shape=(ndim, ndim))
157-
158-
# Solve
159-
w, v = linalg.eigsh(k, k=20, M=m, sigma=10000)
160-
# System natural frequencies
161-
f = (np.real(w))**0.5/(2*np.pi)
162-
163-
print('First four natural frequencies')
164-
for i in range(4):
165-
print '{:.3f} Hz'.format(f[i])
166-
167-
.. code::
168-
169-
First four natural frequencies
170-
1283.200 Hz
171-
1283.200 Hz
172-
5781.975 Hz
173-
6919.399 Hz
174-
175132

176133
Built-In Examples
177134
-----------------

doc/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Contents
1616

1717
examples
1818
loading_results
19+
loading_km
1920

2021
Installation
2122
------------

doc/loading_km.rst

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
Working with a ANSYS Full File (full)
2+
======================================
3+
4+
The ANSYS full file is a fortran formatted binary file containing the mass and
5+
stiffness from an ANSYS analysis. Using pyansys it can be loaded into memory
6+
as either a sparse or full matrix.
7+
8+
9+
Reading a Full File
10+
-------------------
11+
This example reads in the mass and stiffness matrices associated with the above
12+
example. By default, ``LoadKM`` sorts degrees of freedom such that the nodes are
13+
ordered from minimum to maximum, and each degree of freedom (i.e. X, Y, Z), are
14+
sorted within each node. This increases the bandwidth of mass and stiffness
15+
matrices and can be disabled by setting ``sort=False``. The matrices ``k`` and
16+
``m`` are sparse by default, but if ``scipy`` is not installed, or if the
17+
optional parameter ``as_sparse=False`` then they will be full numpy arrays.
18+
19+
.. code:: python
20+
21+
# Load pyansys
22+
import pyansys
23+
24+
# Create result reader object and read in full file
25+
fobj = pyansys.FullReader('file.full')
26+
dof_ref, k, m = fobj.LoadKM()
27+
28+
29+
If you have ``scipy`` installed, you can solve solve for the natural
30+
frequencies of a system.
31+
32+
.. code:: python
33+
34+
from scipy.sparse import linalg
35+
#numpy.linalg.eig
36+
37+
# Solve
38+
w, v = linalg.eigsh(k, k=20, M=m, sigma=10000)
39+
40+
# System natural frequencies
41+
f = (np.real(w))**0.5/(2*np.pi)
42+
43+
print('First four natural frequencies')
44+
for i in range(4):
45+
print '{:.3f} Hz'.format(f[i])
46+
47+
.. code::
48+
49+
First four natural frequencies
50+
1283.200 Hz
51+
1283.200 Hz
52+
5781.975 Hz
53+
6919.399 Hz
54+
55+
This exact example can be run from pyansys's examples::
56+
57+
from pyansys import examples
58+
examples.LoadKM()
59+
60+
61+

pyansys/binary_reader.py

Lines changed: 103 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
import numpy as np
23
import warnings
34
import logging
@@ -79,6 +80,10 @@ def __init__(self, filename):
7980
8081
"""
8182

83+
# check if file exists
84+
if not os.path.isfile(filename):
85+
raise Exception('{:s} not found'.format(filename))
86+
8287
self.filename = filename
8388
self.header = _parsefull.ReturnHeader(filename)
8489

@@ -91,39 +96,44 @@ def __init__(self, filename):
9196
raise Exception ("Unable to read an unsymmetric mass/stiffness matrix.")
9297

9398

94-
def LoadFullKM(self):
99+
def LoadKM(self, as_sparse=True, sort=True):
95100
"""
96-
Load indices for constructing symmetric mass and stiffness
97-
matricies
101+
Load and construct mass and stiffness matrices from an ANSYS full file.
98102
99-
STORES TO SELF:
100-
101-
nref (np.int32 array)
102-
Ordered reference to original ANSYS node numbers
103+
Parameters
104+
----------
105+
as_sparse : bool, optional
106+
Outputs the mass and stiffness matrices as scipy csc sparse arrays
107+
when True by default.
108+
109+
sort : bool, optional
110+
By default, this setting sorts the rows and columns such that the
111+
nodes are in order. ANSYS stores the mass and stiffness matrices
112+
such that the bandwidth of the arrays is minimized. Therefore, to
113+
minimize the bandwidth of the arrays, make this setting False.
114+
103115
104-
dref (np.int32 array)
105-
DOF reference where
116+
Returns
117+
-------
118+
dof_ref : (n x 2) np.int32 array
119+
This array contains the node and degree corresponding to each row
120+
and column in the mass and stiffness matrices. When the sort
121+
parameter is set to True this array will be sorted by node number
122+
first and then by the degree of freedom. In a 3 DOF analysis the
123+
intergers will correspond to:
106124
0 - x
107125
1 - y
108126
2 - z
109-
110-
krows (np.int32 array)
111-
Rows to construct the sparse stiffness matrix
112-
113-
kcols (np.int32 array)
114-
Columns to construct the sparse stiffness matrix
127+
128+
k : (n x n) np.float or scipy.csc array
129+
Stiffness array
130+
131+
m : (n x n) np.float or scipy.csc array
132+
Mass array
133+
134+
Notes
135+
-----
115136
116-
kdata (np.int32 array)
117-
Data for each entry in thesparse stiffness matrix
118-
119-
mrows (np.int32 array)
120-
Rows to construct the mass stiffness matrix
121-
122-
mcols (np.int32 array)
123-
Columns to construct the mass stiffness matrix
124-
125-
mdata (np.int32 array)
126-
Data to construct the mass stiffness matrix
127137
128138
"""
129139
data = _parsefull.ReturnFull_KM(self.filename)
@@ -144,7 +154,54 @@ def LoadFullKM(self):
144154
self.mcols = data[6]
145155
self.mdata = data[7]
146156

147-
157+
# see if
158+
if as_sparse:
159+
try:
160+
from scipy.sparse import csc_matrix
161+
except:
162+
raise Exception('Unable to load scipy, matricies will be full')
163+
as_sparse = False
164+
165+
# number of dimentions and degree of freedom reference
166+
ndim = self.nref.size
167+
dof_ref = np.vstack((self.nref, self.dref)).T
168+
idx, ridx = Unique_Rows(dof_ref)
169+
170+
# resort K and M matries to ordered sorted node order
171+
if sort:
172+
# determine unique nodes and sorted indices
173+
krow = ridx[self.krows]
174+
kcol = ridx[self.kcols]
175+
176+
# get number of degrees of freedom
177+
krow = ridx[self.krows]
178+
kcol = ridx[self.kcols]
179+
mrow = ridx[self.mrows]
180+
mcol = ridx[self.mcols]
181+
182+
# sorted references
183+
dof_ref = dof_ref[idx]
184+
185+
else:
186+
krow = self.krows
187+
kcol = self.kcols
188+
mrow = self.mrows
189+
mcol = self.mcols
190+
191+
# output as a sparse matrix
192+
if as_sparse:
193+
k = csc_matrix((self.kdata, (krow, kcol)), shape=(ndim,)*2)
194+
m = csc_matrix((self.mdata, (mrow, mcol)), shape=(ndim,)*2)
195+
196+
else:
197+
k = np.zeros((ndim,)*2)
198+
k[krow, kcol] = self.kdata
199+
200+
m = np.zeros((ndim,)*2)
201+
m[mrow, mcol] = self.mdata
202+
203+
return dof_ref, k, m
204+
148205

149206
class ResultReader(object):
150207
"""
@@ -153,19 +210,22 @@ class ResultReader(object):
153210

154211
def __init__(self, filename, logger=False):
155212
"""
156-
SUMMARY
157-
Loads basic result information from result file.
158-
213+
Loads basic result information from result file and initializes result
214+
object.
159215
160-
INPUTS
161-
filename (str)
216+
Parameters
217+
----------
218+
filename : string
162219
Filename of the ANSYS binary result file.
220+
221+
logger : bool
222+
Enables logging if True. Debug feature.
163223
164224
165-
OUTPUTS
225+
Returns
226+
-------
166227
None
167228
168-
169229
"""
170230

171231
# set logging level depending on settings
@@ -826,3 +886,12 @@ def GetResultInfo(filename):
826886
return resultheader
827887

828888

889+
890+
def Unique_Rows(a):
891+
""" Returns unique rows of a and indices of those rows """
892+
b = np.ascontiguousarray(a).view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))
893+
_, idx, ridx = np.unique(b, return_index=True, return_inverse=True)
894+
895+
return idx, ridx
896+
897+

pyansys/examples/examples.py

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"""
55

66
from __future__ import print_function
7-
import os
7+
import os, inspect, sys
88

99
import pyansys
1010

@@ -17,6 +17,17 @@
1717
hexbeamfile = os.path.join(dir_path, 'hexbeam.vtk')
1818
fullfile = os.path.join(dir_path, 'file.full')
1919

20+
21+
def RunAll():
22+
""" Runs all the functions within this module """
23+
testfunctions = []
24+
for name, obj in inspect.getmembers(sys.modules[__name__]):
25+
if inspect.isfunction(obj) and name != 'RunAll':
26+
testfunctions.append(obj)
27+
28+
# run all the functions
29+
any(f() for f in testfunctions)
30+
2031

2132
def DisplayHexBeam():
2233
""" Displays a hex beam mesh """
@@ -76,7 +87,7 @@ def LoadKM():
7687

7788
# Create file reader object
7889
fobj = pyansys.FullReader(fullfile)
79-
fobj.LoadFullKM()
90+
dof_ref, k, m = fobj.LoadKM()
8091

8192
ndim = fobj.nref.size
8293

@@ -85,6 +96,23 @@ def LoadKM():
8596
print('\t k has {:d} entries'.format(fobj.krows.size))
8697
print('\t m has {:d} entries'.format(fobj.mrows.size))
8798

99+
# compute natural frequencies if installed
100+
try:
101+
from scipy.sparse import linalg
102+
except:
103+
return
104+
105+
import numpy as np
106+
# Solve
107+
w, v = linalg.eigsh(k, k=20, M=m, sigma=10000)
108+
109+
# System natural frequencies
110+
f = np.real(w)**0.5/(2*np.pi)
111+
112+
print('First four natural frequencies:')
113+
for i in range(4):
114+
print('{:.3f} Hz'.format(f[i]))
115+
88116

89117
def DisplayCellQual(meshtype='tet'):
90118
"""
@@ -120,15 +148,3 @@ def DisplayCellQual(meshtype='tet'):
120148
archive.uGrid.Plot(scalars=qual, stitle='Cell Minimum Scaled\nJacobian',
121149
rng=[0, 1])
122150

123-
124-
125-
def RunAll():
126-
""" Runs all examples in this file """
127-
DisplayCellQual()
128-
DisplayCellQual('hex')
129-
LoadKM()
130-
DisplayHexBeam()
131-
LoadResult()
132-
DisplayDisplacement()
133-
134-

0 commit comments

Comments
 (0)