OpenSees Cloud

OpenSees AMI

Ordinary Eigenvalues

Original Post - 13 Nov 2020 - Michael H. Scott

Visit Structural Analysis Is Simple on Substack.


There are three applications of eigenvalue analysis in structural engineering. Vibration analysis and buckling analysis involve generalized eigenvalue analysis. OpenSees does vibration eigenvalue analysis pretty well, but does not perform buckling eigenvalue analysis–although you might be able to fake the geometric stiffness matrix for simple frame models.

The third application of eigenvalue analysis is ordinary (non-generalized) spectral decomposition of the material stiffness matrix, \({\bf K}{\bf x}=\lambda {\bf x}\), which tells you how a structural model wants to deform. The lower the eigenvalue, \(\lambda\), the easier it is for the model to deform in the shape of the associated eigenvector, \({\bf x}\). If you get a zero eigenvalue, there is a rigid body displacement mode in your model.

There are two approaches to finding the spectral decomposition of the stiffness matrix in OpenSees. The first approach is to use the default generalized eigenvalue solver in OpenSees after making the mass matrix equal to the identity matrix.

#
# Define your model
#

NDF = ops.getNDF()[0]
ones = [1]*NDF # 1,1,...,1
for nd in ops.getNodeTags():
   ops.mass(nd,*ones)

Nmodes = 2 ;# Or whatever
lam = ops.eigen(Nmodes)

The second approach is to use the 'symmBandLapack' option with the eigen command. This is not a generalized eigenvalue solver so you don’t have to worry about the “mass” matrix.

#
# Define your model
#

Nmodes = 2 ;# Or whatever
lam = ops.eigen('standard','symmBandLapack',Nmodes)

The 'standard' input is not entirely necessary. It’s there to make sure you’re aware the eigen command is not going to solve a generalized eigenvalue problem, like clicking “OK” before deleting a file.

There’s a third approach: get the stiffness matrix from printA, then use an eigenvalue solver in Python, e.g., scipy.linalg.eig. This is fine for getting eigenvalues, but you’ll have a hard time mapping the eigenvectors back to the structural model.

Consider a simple beam with two DOFs–the two end rotations. The stiffness matrix contains the basic stiffness coefficients \(4EI/L\) and \(2EI/L\).

IMAGE

The lowest eigenpair \((2EI/L, [1,-1])\) corresponds to symmetric bending, indicating this is the easiest way for the beam to flex while the highest eigenpair \((6EI/L, [1,1])\) corresponds to the more difficult case of anti-symmetric bending. The spectral decomposition tells us that, in the absence of member loads, the flexure of a simple beam is always some combination of symmetric and anti-symmetric bending.

After defining the model and calling the eigen command, you can use the nodeEigenvector command to see the components of the eigenvectors at each node.

import openseespy.opensees as ops

L = 120
E = 29000
A = 12
I = 800

ops.wipe()
ops.model('basic','-ndm',2,'-ndf',3)

ops.node(1,0,0); ops.fix(1,1,1,0)
ops.node(2,L,0); ops.fix(2,1,1,0)

ops.geomTransf('Linear',1)
ops.element('elasticBeamColumn',1,1,2,A,E,I,1)
 
lam = ops.eigen('-standard','-symmBandLapack',2)
 
print('Computed eigenvalues:',lam)
print('Expected eigenvalues:',2*E*I/L,6*E*I/L)

print('Eigenvector 1')
print(ops.nodeEigenvector(1,1,3),ops.nodeEigenvector(2,1,3)) # node, mode, dof
print('Eigenvector 2')
print(ops.nodeEigenvector(1,2,3),ops.nodeEigenvector(2,2,3))

The symmBandLapack eigenvalue solver gives the expected results.

IMAGE

Note that the solver normalized the eigenvectors to have unit length.