OpenSees Cloud
OpenSees AMI
Minimal GimmeMCK Example
Original Post - 24 Sep 2023 - Michael H. Scott
Visit Structural Analysis Is Simple on Substack.
With a title based on a famous ZZ Top song, Gimme All Your Damping, All
Your Mass and Stiffness Too is among the most viewed posts on the blog.
The post describes a transient integrator, GimmeMCK
, that allows you to
extract the damping matrix, or more generally any linear combination of
mass, damping, and stiffness, from an OpenSees model.
In the ZZ Top post, I basically say “define your model, then do
this–and after that, you can also do some state space calculations.”
However, the post did not have a simple, working example of GimmeMCK
in
action.
So, in this post, consider Example 11.1 on page 441 of Chopra, 5th edition.
I’m sure you will find the same example in approximately the same chapter on about the same page in editions 1-4 as well as the newly released 6th edition. [Update: Example 11.1 on page 420 of first edition]
For this model, the mass matrix is:
\[{\bf m} = \left[ \begin{array}{ccc} 1.036 & 0 & 0 \\ 0 & 1.036 & 0 \\ 0 & 0 & 0.518 \end{array} \right]\]While the stiffness matrix is:
\[{\bf k} = \left[ \begin{array}{ccc} 1220 & -610 & 0 \\ -610 & 1220 & -610 \\ 0 & -610 & 610 \end{array} \right]\]The Rayleigh damping matrix assumes 5% damping ratio in the first two modes.
\[{\bf c} = \left[ \begin{array}{ccc} 3.556 & -1.301 & 0 \\ -1.301 & 3.556 & -1.301 \\ 0 & -1.301 & 1.778 \end{array} \right]\]Although the model is a shear frame, in OpenSees you can use zero length elements for the stiffness of each story.
import openseespy.opensees as ops
import numpy as np
g = 386
k = 610
m = 400/g
zeta = 0.05
ops.wipe()
ops.model('basic','-ndm',1,'-ndf',1)
ops.node(0,0); ops.fix(0,1)
ops.node(1,0); ops.mass(1,m)
ops.node(2,0); ops.mass(2,m)
ops.node(3,0); ops.mass(3,m/2)
ops.uniaxialMaterial('Elastic',1,k)
ops.element('zeroLength',1,0,1,'-mat',1,'-dir',1,'-doRayleigh')
ops.element('zeroLength',2,1,2,'-mat',1,'-dir',1,'-doRayleigh')
ops.element('zeroLength',3,2,3,'-mat',1,'-dir',1,'-doRayleigh')
w2 = ops.eigen(2)
wi = w2[0]**0.5
wj = w2[1]**0.5
a1 = zeta*2/(wi+wj)
a0 = a1*wi*wj
ops.rayleigh(a0,0,0,a1)
Be sure to use the -doRayleigh
option for the zero length elements so
that the stiffness proportional damping is assembled.
Then, to pull off GimmeMCK
, you will need to use the FullGeneral
system.
And, although not required, use the Plain
numberer so the DOF numbers
are not scrambled.
ops.numberer('Plain')
ops.system('FullGeneral')
ops.analysis('Transient')
Now you are ready to extract the mass, damping, and stiffness matrices for the model defined above. First, the mass:
ops.integrator('GimmeMCK',1,0,0)
ops.analyze(1,0.0)
N = ops.systemSize()
M = np.array(ops.printA('-ret')).reshape((N,N))
print(M)
Note that you have to do systemSize
after the analyze
command, otherwise
you will get zero equations. Then stiffness and damping–but you could
have extracted the matrices in any order.
ops.integrator('GimmeMCK',0,0,1)
ops.analyze(1,0.0)
K = np.array(ops.printA('-ret')).reshape((N,N))
print(K)
ops.integrator('GimmeMCK',0,1,0)
ops.analyze(1,0.0)
C = np.array(ops.printA('-ret')).reshape((N,N))
print(C)
Verify that you get the expected mass, stiffness, and damping matrices.
Now you are ready use GimmeMCK
on larger models.
Add ZZ Top’s “Concrete and Steel” to the list of structural engineering themed songs.