First, initialize our environment


In [1]:
### Plotting stuff
%matplotlib inline
import matplotlib.pyplot as plt
plt.rcParams['figure.autolayout'] = True
plt.style.use(['fivethirtyeight', './00_mplrc'])
figd = '../figures/05_'

### math stuff
import numpy as np
np.set_printoptions(linewidth=120)
from scipy.linalg import eigh

### format the notebook, ancillary stuff
from IPython.display import display, Latex, HTML
display(HTML(open("00_custom.css", "r").read()))


Next, some handy functions have to be defined...


In [2]:
### A bunch of functions to help with repetitive tasks
def pmat(mat, fmt="%f+8.3", delim="b"):
    "pmat prints an array to be 'copy&paste'd into a LaTeX document"
    print
    print r'\begin{'+delim+'matrix}'
    print '\\\\\n'.join(' & '.join(fmt%n for n in row) for row in mat)
    print r'\end{'+delim+'matrix}' 
    print
##########
def xdot(*mats):
    "xdot(m1,m2, ..., mn) computes a dot product of all the arguments"
    return reduce(np.dot, mats)
##########
def norm(v):
    "norm(v) normalizes a vector so that its norm is 1"
    return v/np.sqrt(np.dot(v, v))
##########
def normalize(thearray, M):
    "normalize(v, M) normalizes a vector so that the norm v.T*M*v is 1"
    return thearray/np.sqrt(np.diag(thearray.T.dot(M.dot(thearray))))

### I've a couple of aux functions to have customized plots of eigenvectors
### in an external module
from eigenplot import plot_evec, plot_ritz

Rayleigh-Ritz and Subspace Iteration

Starting from a flist with the number of each floor, we generate the masses of each floor and the stiffnesses below of each floor, and add an additional, fictitiuos zero stiffness to our list to represent the stiffness of the non-existing post-ultimate floor...

From these lists, using np.diag it's easy to construct the structural matrices.

Eventually we print our structural matrices, using a normalization factor to keep the width of the printing tolerable.


In [3]:
n_floor = range(1,10) # --> (1, ..., 9)
m_floor = [405000. - floor_n*5000. for floor_n in n_floor]
k_floor = [(840-10*(floor_n-1)**2)*1E6 for floor_n in n_floor]
k_floor.append(0.0)

M = np.diag(m_floor)
K = (np.diag(k_floor[:-1]) + 
     np.diag(k_floor[+1:]) -
     np.diag(k_floor[1:-1],k=+1) -
     np.diag(k_floor[1:-1],k=-1))

print ";".join("%d"%(m/1000) for m in m_floor)
print ";".join("%d"%(m/1E6) for m in k_floor)

print 'mass matrix M/1000\n', M/1000
print 'stiffness matrix K/1E6\n', K/1E6
pmat(M/1000, fmt='%d')
pmat(K/1E6, fmt='%d')


400;395;390;385;380;375;370;365;360
840;830;800;750;680;590;480;350;200;0
mass matrix M/1000
[[ 400.    0.    0.    0.    0.    0.    0.    0.    0.]
 [   0.  395.    0.    0.    0.    0.    0.    0.    0.]
 [   0.    0.  390.    0.    0.    0.    0.    0.    0.]
 [   0.    0.    0.  385.    0.    0.    0.    0.    0.]
 [   0.    0.    0.    0.  380.    0.    0.    0.    0.]
 [   0.    0.    0.    0.    0.  375.    0.    0.    0.]
 [   0.    0.    0.    0.    0.    0.  370.    0.    0.]
 [   0.    0.    0.    0.    0.    0.    0.  365.    0.]
 [   0.    0.    0.    0.    0.    0.    0.    0.  360.]]
stiffness matrix K/1E6
[[ 1670.  -830.     0.     0.     0.     0.     0.     0.     0.]
 [ -830.  1630.  -800.     0.     0.     0.     0.     0.     0.]
 [    0.  -800.  1550.  -750.     0.     0.     0.     0.     0.]
 [    0.     0.  -750.  1430.  -680.     0.     0.     0.     0.]
 [    0.     0.     0.  -680.  1270.  -590.     0.     0.     0.]
 [    0.     0.     0.     0.  -590.  1070.  -480.     0.     0.]
 [    0.     0.     0.     0.     0.  -480.   830.  -350.     0.]
 [    0.     0.     0.     0.     0.     0.  -350.   550.  -200.]
 [    0.     0.     0.     0.     0.     0.     0.  -200.   200.]]

\begin{bmatrix}
400 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\
0 & 395 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\
0 & 0 & 390 & 0 & 0 & 0 & 0 & 0 & 0\\
0 & 0 & 0 & 385 & 0 & 0 & 0 & 0 & 0\\
0 & 0 & 0 & 0 & 380 & 0 & 0 & 0 & 0\\
0 & 0 & 0 & 0 & 0 & 375 & 0 & 0 & 0\\
0 & 0 & 0 & 0 & 0 & 0 & 370 & 0 & 0\\
0 & 0 & 0 & 0 & 0 & 0 & 0 & 365 & 0\\
0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 360
\end{bmatrix}


\begin{bmatrix}
1670 & -830 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\
-830 & 1630 & -800 & 0 & 0 & 0 & 0 & 0 & 0\\
0 & -800 & 1550 & -750 & 0 & 0 & 0 & 0 & 0\\
0 & 0 & -750 & 1430 & -680 & 0 & 0 & 0 & 0\\
0 & 0 & 0 & -680 & 1270 & -590 & 0 & 0 & 0\\
0 & 0 & 0 & 0 & -590 & 1070 & -480 & 0 & 0\\
0 & 0 & 0 & 0 & 0 & -480 & 830 & -350 & 0\\
0 & 0 & 0 & 0 & 0 & 0 & -350 & 550 & -200\\
0 & 0 & 0 & 0 & 0 & 0 & 0 & -200 & 200
\end{bmatrix}

Exact eigenvalues and eigenvectors

Instead of computing the exact eigenvalues at the end, we do it immediately using scipy.linalg.eigh (here used as eigh), so that we can do our comparisons while we compute new approximations.


In [4]:
evls, evcs = eigh(K,M,eigvals=(0,2))

Do we want to plot the eigenvectors? Definitely yes!


In [5]:
plot_evec(evcs, 'The "real" lowest 3 eigenvectors',
          save=figd+'real_ev.pdf')
print "The eigenvalues, the natural periods"
print evls
print np.array([2*np.pi/np.sqrt(evl) for evl in evls])
print
print "The eigenvectors"
print evcs


/usr/lib/python2.7/dist-packages/matplotlib/figure.py:1744: UserWarning: This figure includes Axes that are not compatible with tight_layout, so its results might be incorrect.
  warnings.warn("This figure includes Axes that are not "
The eigenvalues, the natural periods
[  52.29337118  324.15615089  814.16393455]
[ 0.86887349  0.34898177  0.22020336]

The eigenvectors
[[  1.02744939e-04  -2.39453512e-04   3.66495256e-04]
 [  2.04138430e-04  -4.44384619e-04   5.93605049e-04]
 [  3.04063352e-04  -5.85875951e-04   5.90606121e-04]
 [  4.02381677e-04  -6.38044086e-04   3.37365159e-04]
 [  4.98907580e-04  -5.78482504e-04  -9.74567254e-05]
 [  5.93354329e-04  -3.89060525e-04  -5.47503329e-04]
 [  6.85204111e-04  -5.77009348e-05  -7.52437593e-04]
 [  7.73290370e-04   4.16507994e-04  -3.85876601e-04]
 [  8.53642047e-04   9.99973748e-04   8.28959566e-04]]

First RR Iteration


In [6]:
phi0 = np.array((( 0.33, 0.67, 1.00, 1.33, 1.67, 2.00, 2.33, 2.67, 3.00),
                  (-1.00,-2.00,-3.00,-3.00,-2.00,-1.00, 0.00, 1.00, 3.00),
                  ( 1.00, 2.00, 2.00, 0.00,-2.00,-2.00, 0.00, 1.00, 3.00))).T
plot_evec(phi0, '$\\Phi_0$, not normalized', save=figd+'phi0_nnorm.pdf')
pmat(phi0.T, fmt='%+05.2f')
phi0 = normalize(phi0, M)
plot_evec(phi0, '$\\Phi_0$, normalized', save=figd+'phi0_norm.pdf')
Mz = np.dot(phi0.T,np.dot(M,phi0))
Kz = np.dot(phi0.T,np.dot(K,phi0))
zvl, zvc = eigh(Kz, Mz)
zvc*= np.sign(phi0.dot(zvc)[-1])
print evls
print zvl
print zvc
plot_ritz(zvc, save=figd+'zvc0.pdf')
plot_evec(np.dot(phi0,zvc), 'The lowest 3 eigenvectors, 1st estimate',
          save=figd+'psi_est0.pdf')
pmat(zvc, fmt='%+9.6f')


\begin{bmatrix}
+0.33 & +0.67 & +1.00 & +1.33 & +1.67 & +2.00 & +2.33 & +2.67 & +3.00\\
-1.00 & -2.00 & -3.00 & -3.00 & -2.00 & -1.00 & +0.00 & +1.00 & +3.00\\
+1.00 & +2.00 & +2.00 & +0.00 & -2.00 & -2.00 & +0.00 & +1.00 & +3.00
\end{bmatrix}

[  52.29337118  324.15615089  814.16393455]
[   52.32283364   351.0697609   1189.51555861]
[[ 0.99902988  0.058682   -0.30369332]
 [-0.01848294  0.96197711 -0.32923397]
 [-0.00332288  0.17829296  1.03498948]]
/usr/lib/python2.7/dist-packages/matplotlib/__init__.py:894: UserWarning: axes.color_cycle is deprecated and replaced with axes.prop_cycle; please use the latter.
  warnings.warn(self.msg_depr % (key, alt_key))
\begin{bmatrix}
+0.999030 & +0.058682 & -0.303693\\
-0.018483 & +0.961977 & -0.329234\\
-0.003323 & +0.178293 & +1.034989
\end{bmatrix}

Second RR iteration

First, the new base $\Phi_1 = K^{-1}M\Phi_0z$


In [7]:
phi1 = xdot(np.linalg.inv(K),M,phi0,zvc)
phi1 = normalize(phi1, M)
display(HTML("<h3>The new base</h3>"))
plot_evec(phi1,'The new Ritz base $\\Phi_1$, normalized',
          save=figd+'phi1_norm.pdf')


The new base

The new estimates


In [8]:
Mz = np.dot(phi1.T,np.dot(M,phi1))
Kz = np.dot(phi1.T,np.dot(K,phi1))
zvl, zvc = eigh(Kz, Mz)
zvc*= np.sign(phi1.dot(zvc)[-1])
print evls
print zvl
print zvc
pmat(zvc, fmt='%+9.6f')
plot_ritz(zvc, save=figd+'zvc1.pdf')
plot_evec(np.dot(phi1,zvc), 'The lowest 3 eigenvectors, 2nd estimate',
          save=figd+'psi_est1.pdf')


[  52.29337118  324.15615089  814.16393455]
[  52.29339843  324.6733187   903.43962384]
[[  9.99993648e-01   1.17959905e-02   2.07491626e-02]
 [ -3.43131373e-04   9.99666494e-01  -4.92997896e-02]
 [ -1.14312444e-04   8.85257904e-03   1.00100320e+00]]

\begin{bmatrix}
+0.999994 & +0.011796 & +0.020749\\
-0.000343 & +0.999666 & -0.049300\\
-0.000114 & +0.008853 & +1.001003
\end{bmatrix}


In [9]:
plot_evec(np.dot(phi1,zvc)-evcs,
          title='Differences, "real" - estimate', save=figd+'diff.pdf')



In [9]: