Using ``cb.cbcheck`` to check mass and stiffness
================================================
This and other jupyter notebooks are available here:
https://github.com/twmacro/pyyeti/tree/master/docs/tutorials.
First, we need a valid Hurty-Craig-Bampton model to work with.
Specifically, we need:
- a-set mass and stiffness
- b-set “uset” table (see description in
`op2.rdnas2cam <../modules/nastran/generated/pyyeti.nastran.op2.rdnas2cam.html#pyyeti.nastran.op2.rdnas2cam>`__)
- Note: this is only needed for statically indeterminate interfaces
- b-set partition vector (relative to a-set)
We’ll use superelement 102 from the test directory:
“tests/nas2cam_csuper”.
Aside:
- “nas2cam” stood for Nastran-to-CAM … CAM is now replaced with Python
but the Nastran DMAP retains the old name.
.. image:: se102.png
--------------
First, do some imports:
.. code:: ipython3
import numpy as np
from io import StringIO
from pyyeti import nastran, cb
from pyyeti.nastran import op4
Need path to data files:
.. code:: ipython3
import os
import inspect
pth = os.path.dirname(inspect.getfile(cb))
pth = os.path.join(pth, 'tests', 'nas2cam_csuper')
Load the mass and stiffness from the .op4 file
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This loads the data into a dict:
.. code:: ipython3
mk = op4.load(os.path.join(pth, 'inboard.op4'))
mk.keys()
.. code-block:: none
odict_keys(['kxx', 'mxx', 'bxx1', 'k4xx1', 'px1', 'gpxx', 'gdxx', 'rvax', 'va', 'mug1', 'mug1o', 'mes1', 'mes1o', 'mee1', 'mee1o', 'mgpfm', 'mgpfb', 'mgpfk', 'mgpfo', 'mef1', 'mef1o', 'mqgm', 'mqgb', 'mqgk', 'mqg1o', 'mqmgm', 'mqmgb', 'mqmgk', 'mqmg1o'])
.. code:: ipython3
maa = mk['mxx'][0]
kaa = mk['kxx'][0]
Get the USET table
^^^^^^^^^^^^^^^^^^
The USET table has the boundary DOF information (id, location,
coordinate system). This is needed for superelements with an
indeterminate interface. The `nastran <../modules/nastran.html>`__
module has the function
`asm2uset <../modules/nastran/generated/pyyeti.nastran.bulk.asm2uset.html#pyyeti.nastran.bulk.asm2uset>`__
(from `nastran.bulk <../modules/nastran/bulk.html>`__, actually) which
is handy for forming the USET table from bulk data.
.. code:: ipython3
uset, coords, bset = nastran.asm2uset(os.path.join(pth, 'inboard.asm'))
# show the coordinates (which are in basic):
uset.loc[(slice(None), 1), :]
.. raw:: html
|
|
nasset |
x |
y |
z |
| id |
dof |
|
|
|
|
| 3 |
1 |
2097154 |
600.0 |
0.0 |
300.0 |
| 11 |
1 |
2097154 |
600.0 |
300.0 |
300.0 |
| 19 |
1 |
2097154 |
600.0 |
300.0 |
0.0 |
| 27 |
1 |
2097154 |
600.0 |
0.0 |
0.0 |
Form-index style b-set partition vector into a-set
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
We already have ``bset``, which is a boolean partition vector for the
b-set:
.. code:: ipython3
bset
.. code-block:: none
array([ True, True, True, True, True, True, True, True, True,
True, True, True, True, True, True, True, True, True,
True, True, True, True, True, True, False, False, False,
False, False, False, False, False], dtype=bool)
Convert to index-style for
`cbcheck <../modules/generated/pyyeti.cb.cbcheck.html#pyyeti.cb.cbcheck>`__:
.. code:: ipython3
b = bset.nonzero()[0]
b
.. code-block:: none
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23])
--------------
Run cbcheck
^^^^^^^^^^^
Write to a string so we can look at the output a section at a time. The
``em_filt`` option filters the effective mass table print to only modes
with 2% or higher values.
.. code:: ipython3
with StringIO() as f:
chk = cb.cbcheck(f, maa, kaa, b, b[:6], uset, em_filt=2)
output = f.getvalue().splitlines()
lines = output[:]
.. code-block:: none
Iteration 1 completed
Convergence: 4 of 6, tolerance range after 2 iterations is [8.182691848294101e-10, 1.8140751429714126e-05]
Convergence: 6 of 6, tolerance range after 3 iterations is [1.9250378964386486e-12, 2.6983748323338855e-11]
First, a note on *possible* output from
`cbcheck <../modules/generated/pyyeti.cb.cbcheck.html#pyyeti.cb.cbcheck>`__
about iterations and convergence. That is information from the “subspace
iteration” eigensolver
`pyyeti.ytools.eig_si <../modules/generated/pyyeti.ytools.eig_si.html#pyyeti.ytools.eig_si>`__.
That routine is called to clean up the lowest frequency modes that are
computed by
`scipy.la.eigh `__
– which can be slightly off. That output is not produced for this case,
since a more general eigensolver is called; this is because (as we’ll
see) the mass fails the positive-definite check and the stiffness fails
the symmetry check.
Before going through the text output of
`cbcheck <../modules/generated/pyyeti.cb.cbcheck.html#pyyeti.cb.cbcheck>`__,
let’s take a quick look at the SimpleNamespace that it returns:
.. code:: ipython3
from pyyeti.pp import PP
PP(chk)
.. code-block:: none
[n=10]
.m : float64 ndarray 1024 elems: (32, 32)
.k : float64 ndarray 1024 elems: (32, 32)
.bset : int64 ndarray 24 elems: (24,)
.rbs : float64 ndarray 192 elems: (32, 6)
.rbg : float64 ndarray 144 elems: (24, 6)
.rbe : float64 ndarray 192 elems: (32, 6)
.uset : pandas DataFrame: (24, 4)
.effmass : pandas DataFrame: (8, 6)
.effmass_percent: pandas DataFrame: (8, 6)
.cb_frq : float64 ndarray 8 elems: (8,) [ 6.12934551 6.13 <...> 281.94904595 424.81380598]
.. code-block:: none
The SimpleNamespace contains the reordered and converted versions of the
inputs, three different sets of rigid-body modes (stiffness-based,
eigenvalue-based, and geometry-based), the Hurty-Craig-Bampton fixed
base frequencies (Hz), and some modal effective mass tables (one in mass
units, the other in percent of total). The documentation below will
cover some of these items in more detail. The following shows the
``.effmass_percent`` DataFrame for this model. The first mode contains
31.9% of the mass in the ‘T2’ direction and 63.7% of the inertia about
the ‘R3’ axis. It also has no mass moving in the ‘T1’ direction. You can
compare the DataFrame shown to the values printed in the text output at
the end of this tutorial.
Note: A zero modal effective mass value actually just means that the
masses sum to zero in that direction for that mode; which is always the
case for flexible (non-rigid) free-free modes.
.. code:: ipython3
chk.effmass_percent
.. raw:: html
|
T1 |
T2 |
T3 |
R1 |
R2 |
R3 |
| Frq (Hz) |
|
|
|
|
|
|
| 6.129346 |
4.263948e-22 |
3.192650e+01 |
6.062466e+00 |
22.622180 |
12.096581 |
63.679236 |
| 6.130134 |
1.191902e-21 |
6.064688e+00 |
3.193021e+01 |
3.493506 |
63.676216 |
12.092146 |
| 23.631877 |
2.593727e-04 |
1.747014e-23 |
8.146329e-25 |
25.133696 |
0.000004 |
0.000004 |
| 70.510647 |
2.258256e-23 |
3.078194e+01 |
9.046811e-01 |
7.263860 |
0.385570 |
13.090706 |
| 70.791530 |
5.463248e-22 |
9.051993e-01 |
3.091302e+01 |
14.573466 |
13.143242 |
0.384697 |
| 104.808515 |
4.446573e+01 |
7.296792e-22 |
7.272231e-21 |
0.000663 |
0.761462 |
0.761462 |
| 281.949046 |
1.274425e-18 |
2.991820e-01 |
2.968974e-03 |
0.083370 |
0.001027 |
0.090367 |
| 424.813806 |
3.418328e-16 |
1.249101e-02 |
4.133089e-01 |
0.096965 |
0.114215 |
0.006029 |
We’ll now focus on the text output of
`cbcheck <../modules/generated/pyyeti.cb.cbcheck.html#pyyeti.cb.cbcheck>`__.
First, we’ll define a simple printing function for cleaner output
viewing:
.. code:: ipython3
def prt(lines, next_string):
for n, line in enumerate(lines):
if next_string in line:
break
else:
n += 1
print('\n'.join(lines[:n]))
return lines[n:]
--------------
The first 13 lines contain summary information. In this case, we see a
warning that the mass is not positive definite and the stiffness is not
symmetric. This doesn’t necessarily mean the model is bad; it could be
that it’s just a little off from perfect. Everything else is as it
should be:
.. code:: ipython3
lines = prt(lines, 'properly restrain')
.. code-block:: none
Mass matrix is symmetric.
Warning: mass matrix is not positive-definite.
However, subspace iteration succeeded, which means the mass
must be close to positive-definite.
Warning: stiffness matrix is not symmetric: abs-max-err = 5.96e-07
Mass values check:
Maximum value of diag(MQQ)-1.0 = 0 (should be zero) Okay
Maximum off-diagonal value of MQQ = 0 (should be zero) Okay
Stiffness values checks:
Maximum value of KBB = 3.80413e+09 (should be zero only if statically-determinate) check
Maximum value of KBQ = 0 (should be zero) Okay
Maximum off-diagonal value of KQQ = 0 (should be zero) Okay
Minimum diagonal value of KQQ = 1483.16 (should be > zero) Okay
Since the stiffness didn’t pass the symmetry check, it’s worthwhile to
print a check value. Comparing this value to the maximum KBB value
(above) shows that the stiffness is *very* close to symmetric:
.. code:: ipython3
abs(kaa-kaa.T).max()
.. code-block:: none
5.9604644775390625e-07
--------------
Next, for statically-indeterminate models, there is a check to see if
the ``bref`` DOF properly restrain rigid-body motion. This is similar to
the SUPORT card in Nastran.
For this model, the check passes. If it failed, it would say: “Check:
FAIL. Assess values below before running CLA.” instead of: “Check: PASS.
Values printed below for reference.”.
The only large percent differences are for numerical zeros.
.. code:: ipython3
lines = prt(lines, 'Stiffness-based coordinates')
.. code-block:: none
Checking to see if reference DOF properly restrain rigid-body motion.
Splitting "kbb" into the "r" (reference) and "o" (other) sets, this should be zero:
krr - kro @ inv(koo) @ kor
Check: PASS. Values printed below for reference.
"krr" is:
[[ 4.35e+05 1.58e+06 -1.58e+06 -1.59e-07 -1.10e+07 -1.10e+07]
[ 1.58e+06 9.53e+06 -9.31e+06 1.76e+07 2.05e+07 2.42e+07]
[ -1.58e+06 -9.31e+06 9.53e+06 1.76e+07 -2.42e+07 -2.05e+07]
[ -1.78e-07 1.76e+07 1.76e+07 3.80e+09 -3.14e+08 3.14e+08]
[ -1.10e+07 2.05e+07 -2.42e+07 -3.14e+08 2.18e+09 1.39e+09]
[ -1.10e+07 2.42e+07 -2.05e+07 3.14e+08 1.39e+09 2.18e+09]]
"kro @ inv(koo) @ kor" is:
[[ 4.35e+05 1.58e+06 -1.58e+06 1.33e-06 -1.10e+07 -1.10e+07]
[ 1.58e+06 9.53e+06 -9.31e+06 1.76e+07 2.05e+07 2.42e+07]
[ -1.58e+06 -9.31e+06 9.53e+06 1.76e+07 -2.42e+07 -2.05e+07]
[ 4.44e-07 1.76e+07 1.76e+07 3.80e+09 -3.14e+08 3.14e+08]
[ -1.10e+07 2.05e+07 -2.42e+07 -3.14e+08 2.18e+09 1.39e+09]
[ -1.10e+07 2.42e+07 -2.05e+07 3.14e+08 1.39e+09 2.18e+09]]
and the difference is:
[[ -3.78e-08 -2.10e-09 -1.63e-09 -1.49e-06 4.35e-06 5.52e-06]
[ -1.86e-09 4.10e-08 1.30e-08 8.62e-06 -1.97e-06 1.64e-05]
[ 0.00e+00 1.12e-08 5.03e-08 1.12e-05 -1.55e-05 2.96e-06]
[ -6.21e-07 5.89e-06 8.59e-06 5.53e-03 -2.18e-03 3.48e-03]
[ 4.17e-06 -2.06e-06 -1.42e-05 -1.80e-03 1.15e-02 -1.36e-03]
[ 5.38e-06 1.73e-05 1.99e-06 3.53e-03 -1.35e-03 9.74e-03]]
The percent difference is:
[[ 0. 0. -0. -937.6 0. 0. ]
[ 0. -0. 0. -0. 0. -0. ]
[ -0. 0. -0. -0. -0. 0. ]
[-349.7 -0. -0. -0. -0. -0. ]
[ 0. 0. -0. -0. -0. 0. ]
[ 0. -0. 0. -0. 0. -0. ]]
--------------
The next section shows coordinate location information as computed from
the stiffness. This first node is the reference and the others are
relative to that node (and in the coordinate system of that node). The
largest coordinate location error is printed for inspection. Here, the
error is very small.
.. code:: ipython3
lines = prt(lines, 'RB Translation')
.. code-block:: none
Stiffness-based coordinates relative to node starting at row/col 1 (after any reordering):
(Note: locations are in local coordinate system of the reference node.)
Node ID X Y Z Error
------ -------- -------- -------- -------- ----------
1 3 0.00 0.00 0.00 0.0000e+00
2 11 0.00 300.00 -0.00 2.1876e-09
3 19 -0.00 300.00 -300.00 2.0272e-09
4 27 -0.00 0.00 -300.00 2.4139e-09
Maximum absolute coordinate location error: 2.41391e-09 units
--------------
The next section shows checks displacements results from rigid-body
motion. All three types of rigid-body modes are used. Here everything is
1.000, perfect.
.. code:: ipython3
lines = prt(lines, 'MASS PROPERTIES CHECKS')
.. code-block:: none
RB Translation Movement Check
-- should all be 1.0s (can be 0.0 for DOF with zero stiffness):
Node Stiffness-based Geometry-based Eigenvalue-based
--------- ------------------- ------------------- -------------------
3 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
11 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
19 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
27 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
RB Rotation Movement Check
-- should all be 1.0s (can be 0.0 for DOF with zero stiffness):
Node Stiffness-based Geometry-based Eigenvalue-based
--------- ------------------- ------------------- -------------------
3 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
11 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
19 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
27 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
--------------
The next section prints the 3 6x6 mass matrices for inspection.
Information derived from these is printed afterwards. Note that the
geometry reference point is different from the other two (see the
`cbcheck <../modules/generated/pyyeti.cb.cbcheck.html#pyyeti.cb.cbcheck>`__
input). Since we didn’t set it, the reference for the geometry-based rb
modes is (0, 0, 0) in the basic system.
.. code:: ipython3
lines = prt(lines, 'Comparisons from mass properties')
.. code-block:: none
MASS PROPERTIES CHECKS:
6x6 mass matrix from stiffness-based rb modes:
1.7551 0.0000 -0.0000 -0.0000 -263.2578 -263.2578
0.0000 1.7551 -0.0000 263.2578 0.0000 772.2199
-0.0000 -0.0000 1.7551 263.2578 -772.2199 -0.0000
-0.0000 263.2578 263.2578 114882.5343 -115832.9863 115832.9863
-263.2578 0.0000 -772.2199 -115832.9863 747465.3910 39598.2243
-263.2578 772.2199 -0.0000 115832.9863 39598.2243 747465.3910
6x6 mass matrix from geometry-based rb modes:
1.7551 0.0000 -0.0000 -0.0000 263.2578 -263.2578
0.0000 1.7551 -0.0000 -263.2578 0.0000 1825.2510
-0.0000 -0.0000 1.7551 263.2578 -1825.2510 -0.0000
-0.0000 -263.2578 263.2578 114882.5343 -273787.6507 -273787.6507
263.2578 0.0000 -1825.2510 -273787.6507 2305947.9390 -39379.1078
-263.2578 1825.2510 -0.0000 -273787.6507 -39379.1078 2305947.9390
6x6 mass matrix from eigensolution-based rb modes:
1.7551 0.0000 -0.0000 -0.0000 -263.2578 -263.2578
0.0000 1.7551 -0.0000 263.2578 0.0000 772.2199
-0.0000 -0.0000 1.7551 263.2578 -772.2199 0.0000
-0.0000 263.2578 263.2578 114882.5343 -115832.9863 115832.9863
-263.2578 0.0000 -772.2199 -115832.9863 747465.3910 39598.2243
-263.2578 772.2199 0.0000 115832.9863 39598.2243 747465.3910
--------------
CG location comparison is next:
.. code:: ipython3
lines = prt(lines, 'Radius of gyration')
.. code-block:: none
Comparisons from mass properties:
Distance to CG location from relevant reference point:
RB-Mode from X Y Z
------------ ---------------------------------------------
Stiffness 439.998351 150.000000 -150.000000
Geometry 1039.998351 150.000000 150.000000
Eigensolution 439.998351 150.000000 -150.000000
--------------
Radius of gyration checks are next. The radius of gyration about an axis
is the radius where all the mass would be if all the mass were at a
single radius. These values should make sense with your structure. If a
radius is beyond your dimensions for example, you know something is
wrong (yes, this has happened … due to a badly written CONM1 or CONM2
Nastran card).
.. code:: ipython3
lines = prt(lines, 'Stiffness-based Inertia')
.. code-block:: none
Radius of gyration about X, Y, Z axes (from CG):
RB-Mode from X Y Z
------------ ---------------------------------------------
Stiffness 143.032166 458.033929 458.033929
Geometry 143.032166 458.033929 458.033929
Eigensolution 143.032166 458.033929 458.033929
Radius of gyration about principal axes (from CG):
RB-Mode from 1 2 3
------------ ---------------------------------------------
Stiffness 143.032166 457.965780 458.102068
Geometry 143.032166 457.965780 458.102068
Eigensolution 143.032166 457.965780 458.102068
--------------
Inertia values are printed next for inspection:
.. code:: ipython3
lines = prt(lines, 'GROUNDING CHECKS')
.. code-block:: none
Stiffness-based Inertia Matrix @ CG about X,Y,Z:
35905.2022 0.0000 -0.0000
0.0000 368201.2386 109.5583
-0.0000 109.5583 368201.2386
Principal Axis Moments of Inertia:
35905.2022 368091.6803 368310.7968
Geometry-based Inertia Matrix @ CG about X,Y,Z:
35905.2022 -0.0000 0.0000
-0.0000 368201.2386 109.5583
0.0000 109.5583 368201.2386
Principal Axis Moments of Inertia:
35905.2022 368091.6803 368310.7968
Eigensolution-based Inertia Matrix @ CG about X,Y,Z:
35905.2022 0.0000 0.0000
0.0000 368201.2386 109.5583
0.0000 109.5583 368201.2386
Principal Axis Moments of Inertia:
35905.2022 368091.6803 368310.7968
--------------
Grounding checks are next. This is likely the largest section. This
model is very clean. Note that the grounding forces for the
geometry-based rigid-body modes can only include the b-set while the
other two include the q-set.
If the stiffness and eigenvalue based checks are good, but the geometry
one is not good, it probably means you have a mistake in your USET table
(bad coordinate system, incorrect grid location, or the grids are in the
wrong order).
.. code:: ipython3
lines = prt(lines, 'FREE-FREE MODES')
.. code-block:: none
GROUNDING CHECKS:
K*RB using stiffness-based rb modes:
DOF X Y Z RX RY RZ
------------- --------------------------------------------------------------------
3 1 -0.000 -0.000 -0.000 -0.000 0.000 0.000
3 2 -0.000 0.000 0.000 0.000 -0.000 0.000
3 3 0.000 0.000 0.000 0.000 -0.000 0.000
3 4 -0.000 0.000 0.000 0.005 -0.002 0.003
3 5 0.000 -0.000 -0.000 -0.002 0.012 -0.001
3 6 0.000 0.000 0.000 0.004 -0.001 0.010
11 1 -0.000 -0.000 -0.000 -0.000 0.000 -0.000
11 2 -0.000 -0.000 0.000 -0.000 0.000 -0.000
11 3 0.000 0.000 -0.000 0.000 0.000 0.000
11 4 0.000 0.000 -0.000 0.000 -0.000 0.000
11 5 0.000 -0.000 -0.000 0.000 0.000 -0.000
11 6 -0.000 -0.000 0.000 -0.000 0.000 -0.000
19 1 -0.000 0.000 -0.000 0.000 0.000 -0.000
19 2 0.000 0.000 0.000 -0.000 -0.000 0.000
19 3 -0.000 -0.000 0.000 -0.000 0.000 -0.000
19 4 -0.000 0.000 -0.000 -0.000 -0.000 -0.000
19 5 -0.000 -0.000 -0.000 0.000 0.000 -0.000
19 6 -0.000 0.000 -0.000 0.000 0.000 -0.000
27 1 0.000 0.000 -0.000 0.000 -0.000 0.000
27 2 0.000 0.000 -0.000 0.000 -0.000 0.000
27 3 0.000 0.000 -0.000 0.000 -0.000 0.000
27 4 0.000 0.000 -0.000 0.000 -0.000 -0.000
27 5 -0.000 -0.000 -0.000 -0.000 0.000 -0.000
27 6 0.000 -0.000 -0.000 0.000 -0.000 0.000
modal 1 0.000 0.000 0.000 0.000 0.000 0.000
modal 2 0.000 0.000 0.000 0.000 0.000 0.000
modal 3 0.000 0.000 0.000 0.000 0.000 0.000
modal 4 0.000 0.000 0.000 0.000 0.000 0.000
modal 5 0.000 0.000 0.000 0.000 0.000 0.000
modal 6 0.000 0.000 0.000 0.000 0.000 0.000
modal 7 0.000 0.000 0.000 0.000 0.000 0.000
modal 8 0.000 0.000 0.000 0.000 0.000 0.000
Summation of stiffness-based rb-forces: RB'*K*RB:
-0.000 -0.000 -0.000 -0.000 0.000 0.000
-0.000 0.000 0.000 0.000 -0.000 0.000
0.000 0.000 0.000 0.000 -0.000 0.000
-0.000 0.000 0.000 0.005 -0.002 0.004
0.000 -0.000 -0.000 -0.002 0.012 -0.001
0.000 0.000 0.000 0.003 -0.001 0.010
K*RB using geometry-based rb modes:
DOF X Y Z RX RY RZ
------------- --------------------------------------------------------------------
3 1 -0.000 0.000 -0.000 -0.000 0.000 0.000
3 2 -0.000 0.000 -0.000 -0.000 0.000 0.000
3 3 0.000 -0.000 0.000 0.000 -0.000 -0.000
3 4 -0.000 -0.000 -0.000 -0.000 0.000 -0.001
3 5 0.000 -0.000 0.000 0.000 -0.001 -0.003
3 6 0.000 -0.000 0.000 0.000 -0.003 -0.001
11 1 0.000 0.000 0.000 -0.000 -0.000 0.000
11 2 0.000 0.000 0.000 0.000 -0.000 0.000
11 3 -0.000 -0.000 -0.000 0.000 0.000 -0.000
11 4 0.000 0.000 0.000 -0.000 -0.002 0.003
11 5 -0.000 -0.000 -0.000 -0.000 0.003 -0.002
11 6 0.000 -0.000 0.000 -0.000 -0.001 -0.000
19 1 -0.000 -0.000 0.000 0.000 -0.000 -0.000
19 2 0.000 0.000 -0.000 0.000 0.000 0.000
19 3 -0.000 -0.000 0.000 0.000 -0.000 -0.000
19 4 0.000 0.000 0.000 -0.000 -0.001 0.001
19 5 0.000 -0.000 0.000 0.000 -0.001 -0.003
19 6 0.000 -0.000 0.000 0.000 -0.003 -0.001
27 1 -0.000 0.000 0.000 -0.000 -0.000 0.000
27 2 -0.000 0.000 0.000 0.000 -0.000 0.000
27 3 -0.000 0.000 0.000 -0.000 -0.000 0.000
27 4 -0.000 0.000 -0.000 -0.000 0.000 0.000
27 5 -0.000 0.000 0.000 -0.000 -0.002 0.003
27 6 -0.000 -0.000 -0.000 -0.000 0.003 -0.002
Summation of geometry-based rb-forces: RB'*K*RB:
-0.000 -0.000 -0.000 -0.000 -0.000 0.000
-0.000 0.000 0.000 -0.000 -0.000 0.000
0.000 0.000 0.000 0.000 -0.000 0.000
0.000 -0.000 0.000 0.005 -0.006 -0.007
-0.000 -0.000 -0.000 -0.005 0.050 -0.005
0.000 0.000 0.000 -0.004 -0.005 0.048
K*RB using eigensolution-based rb modes:
DOF X Y Z RX RY RZ
------------- --------------------------------------------------------------------
3 1 -0.000 0.000 -0.000 0.000 0.000 0.000
3 2 -0.000 0.000 -0.000 0.000 0.000 0.000
3 3 0.000 -0.000 0.000 -0.000 -0.000 -0.000
3 4 0.000 -0.000 -0.000 -0.000 0.000 -0.000
3 5 0.000 -0.000 0.000 -0.000 -0.001 -0.001
3 6 0.000 -0.000 0.000 -0.000 -0.002 -0.001
11 1 0.000 -0.000 0.000 -0.000 -0.000 -0.000
11 2 0.000 0.000 0.000 0.000 -0.000 0.000
11 3 -0.000 -0.000 -0.000 -0.000 0.000 -0.000
11 4 0.000 0.000 0.000 0.000 -0.001 0.001
11 5 -0.000 -0.000 -0.000 -0.000 0.002 -0.001
11 6 0.000 -0.000 0.000 -0.000 -0.000 -0.000
19 1 -0.000 -0.000 0.000 -0.000 -0.000 -0.000
19 2 0.000 0.000 -0.000 0.000 0.000 -0.000
19 3 -0.000 -0.000 0.000 0.000 0.000 -0.000
19 4 0.000 0.000 0.000 -0.000 -0.000 0.000
19 5 -0.000 -0.000 0.000 -0.000 -0.001 -0.001
19 6 -0.000 -0.000 0.000 0.000 -0.002 -0.000
27 1 -0.000 0.000 0.000 0.000 -0.000 0.000
27 2 -0.000 0.000 0.000 0.000 -0.000 0.000
27 3 -0.000 0.000 0.000 0.000 -0.000 0.000
27 4 -0.000 0.000 -0.000 -0.000 0.000 0.000
27 5 0.000 0.000 0.000 0.000 -0.001 0.001
27 6 -0.000 -0.000 -0.000 -0.000 0.002 -0.001
modal 1 0.000 -0.000 0.000 -0.000 -0.000 -0.000
modal 2 0.000 0.000 0.000 0.000 -0.000 0.000
modal 3 0.000 0.000 0.000 -0.000 -0.000 -0.000
modal 4 -0.000 0.000 0.000 0.000 0.000 0.000
modal 5 0.000 0.000 -0.000 0.000 -0.000 -0.000
modal 6 -0.000 0.000 -0.000 0.000 -0.000 0.000
modal 7 -0.000 0.000 -0.000 -0.000 0.000 0.000
modal 8 -0.000 0.000 -0.000 0.000 0.000 0.000
Summation of eigensolution-based rb-forces: RB'*K*RB:
-0.000 -0.000 -0.000 -0.000 0.000 0.000
-0.000 0.000 0.000 0.000 -0.000 0.000
0.000 0.000 0.000 0.000 -0.000 0.000
-0.000 0.000 0.000 0.005 -0.002 0.004
0.000 -0.000 -0.000 -0.002 0.012 -0.001
0.000 0.000 0.000 0.003 -0.001 0.010
--------------
The free-free mode check is next. The rigid-body modes should be close
to zero frequency. (I actually depend on this more than the grounding
checks above to check for grounding.) As noted previously, this model is
very clean.
.. code:: ipython3
lines = prt(lines, 'Modal Effective Mass')
.. code-block:: none
FREE-FREE MODES:
Mode Frequency (Hz)
---- --------------
1 0.000024
2 0.000012
3 0.000020
4 0.000023
5 0.000032
6 0.000046
7 47.926681
8 47.985939
9 53.273647
10 137.646420
11 156.953727
12 158.291832
13 245.776945
14 245.776945
15 278.650359
16 291.228161
17 296.280852
18 304.217218
19 429.385190
20 1479.543087
21 1509.151143
22 1611.251104
23 2421.562811
24 2421.562963
25 2520.830498
--------------
The last section prints the modal effective mass using the
geometry-based rb modes. This should match the provided documentation if
there is any.
.. code:: ipython3
lines = prt(lines, 'end of file')
.. code-block:: none
FIXED-BASE MODES w/ Percent Modal Effective Mass:
Using geometry-based rb modes for effective mass calcs.
Printing only the modes with at least 2.0% effective mass.
The sum includes all modes.
Mode No. Frequency (Hz) T1 T2 T3 R1 R2 R3
-------- -------------- ------ ------ ------ ------ ------ ------
1 6.129 0.00 31.93 6.06 22.62 12.10 63.68
2 6.130 0.00 6.06 31.93 3.49 63.68 12.09
3 23.632 0.00 0.00 0.00 25.13 0.00 0.00
4 70.511 0.00 30.78 0.90 7.26 0.39 13.09
5 70.792 0.00 0.91 30.91 14.57 13.14 0.38
6 104.809 44.47 0.00 0.00 0.00 0.76 0.76
Total Effective Mass: 44.47 69.99 70.23 73.27 90.18 90.10