## Introduction

Approximate method for structural analysis is frequently used among civil engineers. This method is most effective while designing a building. This method is also useful for analysing other structure. But in this blog we will talk about analysis building frame with approximate method and at the end we will discuss how this can be done using python language. Python code will be provided. This script can also be used for analysing other building frame by changing loads and dimensions.

## Approximate method

First we will talk about approximate method. In this post we will discuss about the part of the approximate which is used solving building frame. The most popular one is the portal method which is used for lateral loads. The other technique is solving for gravity loads.

### Portal method for lateral loads

The portal method for analysing fixed-supported building frames requires some assumptions discussed below.

• Since it is assumed that the point of inflection is the place of zero moment and it is found at the centre of each member. That is why a hinge is placed at the centre of each beam and column member.
• Shear at the interior column hinges is assumed twice that at the exterior column hinges, as the frame is considered to be a superposition of portals.

### Python code for solving building frame by portal method

The provided python code can be used for solving portal frame under lateral loading. Dimensions, load, storey and number of bay can be changed in the script. Note that, force unit is in kilo-pound and length is in feet.

### Script

```import numpy as np
import matplotlib.patches as patches
import matplotlib.pyplot as plt

height = 10 # Floor height
storey = 6
bay = 2
bay_widths = np.array([13.125, 13.42])
#force_list = np.array([10, 8.5, 7, 5, 3.5, 2])
force_list = np.array([2, 3.5, 5, 7, 8.5, 10])

bay_widths_cm = np.hstack((0,bay_widths.cumsum()))
heights = height*np.ones(storey)
heights_cm = np.hstack((0,heights.cumsum()))

h_line = storey*bay
v_line = (bay+1)*storey

def frame():
fig= plt.figure(figsize=(10,10))

for i in range(storey):
for j in range(bay):
ax.plot([bay_widths_cm[j],bay_widths_cm[j+1]],[heights_cm[i+1], heights_cm[i+1]], color='blue') #Horizontal line

for i in range(storey):
for j in range(bay+1):
ax.plot([bay_widths_cm[j], bay_widths_cm[j]], [heights_cm[i], heights_cm[i+1]], color='blue')
return fig, ax

fig, ax = frame()
for i in range(storey):
arl = 5
ax.annotate(str(force_list[i]), xytext=[-arl, heights_cm[i+1]-0.7],
xy=[0, heights_cm[i+1]],
arrowprops=dict(arrowstyle="->", color='red'),
fontsize=12, size=20)
ax.set_xlim(-bay_widths*0.3, np.max(bay_widths_cm) + bay_widths*0.3)

shear_unit = force_list[::-1].cumsum()/(bay*2)
csf = np.zeros((storey, bay+1))
csf_shape=np.shape(csf) #shear force for column
cmt = np.zeros((storey, bay+1))#Bending moment for column
bmt = np.zeros((storey, bay))#Bending moment for beam
for i in range(storey):
csf[i]=shear_unit[i]*2
csf[i, 0] = shear_unit[i]
csf[i, -1] = shear_unit[i]

## Shear force diagram for column
fig_f, ax_f = frame()
for i in range(storey):
for j in range(bay+1):
ax_f.text(bay_widths_cm[j], heights_cm[i]+(height/2) , csf[::-1][i,j])
rect = patches.Rectangle((bay_widths_cm[j],heights_cm[i]),
csf[::-1][i,j]*0.4,height,linewidth=1,edgecolor='r',facecolor='green', alpha=0.5)
#ax_f.text(bay_widths_cm[j]-2, heights_cm[i]+1 , csf[::-1][i,j]*height*0.5)
#ax_f.text(bay_widths_cm[j]-2, heights_cm[i]+height-1.5 , csf[::-1][i,j]*height*0.5)
ax_f.set_xlim(-bay_widths*0.3, np.max(bay_widths_cm) + bay_widths*0.3)
fig_f.savefig('Shear_force_column.png', dpi=300)

## Bending moment diagram for column

fig_g, ax_g = frame()
for i in range(storey):
for j in range(bay+1):
mnt = csf[::-1][i,j] * height/2
cmt[i,j]=mnt
ax_g.text(bay_widths_cm[j], heights_cm[i]+(height/2) , mnt)
#rect = patches.Rectangle((bay_widths_cm[j],heights_cm[i]),
#                         csf[::-1][i,j]*0.4,height,linewidth=1,edgecolor='r',facecolor='none')
ax_g.plot([bay_widths_cm[j], bay_widths_cm[j]+(mnt*0.05),  bay_widths_cm[j]-(mnt*0.05), bay_widths_cm[j]],
[heights_cm[i], heights_cm[i], heights_cm[i]+height, heights_cm[i]+height],
color='red')

ax_g.set_xlim(-bay_widths*0.3, np.max(bay_widths_cm) + bay_widths*0.3)
fig_g.savefig('Moment_diagram_column.png', dpi=300)

## Bending moment diagram for Beam

fig_h, ax_h = frame()
for i in range(storey):
for j in range(bay):
bmb = (cmt[i,0]+cmt[i+1,0]) if i+1<=storey-1 else cmt[i,0]
bmt[i,j]=bmb
ax_h.text((bay_widths_cm[j]+bay_widths_cm[j+1])/2, heights_cm[i+1] , bmb)
ax_h.plot([bay_widths_cm[j], bay_widths_cm[j], bay_widths_cm[j+1], bay_widths_cm[j+1]],
[heights_cm[i+1], heights_cm[i+1]+(bmb*0.04), heights_cm[i+1]-(bmb*0.04), heights_cm[i+1]], color='red')
#print ('Storey:',i,'Bay:',j,'Column_shear:',bmb)
#ax_g.text(bay_widths_cm[j], heights_cm[i]+(height/2) , mnt)

ax_h.set_xlim(-bay_widths*0.3, np.max(bay_widths_cm) + bay_widths*0.3)
fig_h.savefig('Moment_diagram_beam.png', dpi=300)

## Shear force diagram beam

fig_i, ax_i = frame()
for i in range(storey):
for j in range(bay):
sf = np.round(bmt[i,j]/(bay_widths[j]*0.5),2) #Shear force
ax_i.text((bay_widths_cm[j]+bay_widths_cm[j+1])/2, heights_cm[i+1] , sf)
#ax_i.plot([bay_widths_cm[j], bay_widths_cm[j], bay_widths_cm[j+1], bay_widths_cm[j+1]],
#          [heights_cm[i+1], heights_cm[i+1]+(sf*0.4), heights_cm[i+1]+(sf*0.4), heights_cm[i+1]], color='red')

rect = patches.Rectangle((bay_widths_cm[j],heights_cm[i+1]),
bay_widths[j],sf*0.4,linewidth=1,edgecolor='r',facecolor='green', alpha=0.5)

ax_i.set_xlim(-bay_widths*0.3, np.max(bay_widths_cm) + bay_widths*0.3)
fig_i.savefig('Shear_diagram_beam.png', dpi=300)

```

### Approximate method for distributed gravity loads

The assumptions to make a building frame statically determinate for distributed gravity load are as follows.

• Zero moment is assumed to be found at 0.1L from the left support for a beam.
• Zero moment is assumed to be found at 0.1L from the right support for a beam.
• The axial force in a beam is assumed to be zero.

For the first two assumptions, the basis is, the support of a beam of a building frame does not behave completely fixed support. This is somewhere between a simply supported beam and a pure fixed end beam. For a fixed end, the moment is zero at 0.21L distance. So, for a building frame this is average of (0+0.21L)/2~0.1L. As for simply supported beam the moment is zero at distance zero. The figures below will clear this phenomena.

### Python code for solving building frame for distributed gravity loads

The provided python code can be used for solving building frame under distributed gravity loading as shown in the figure above. Dimensions, load, storey and number of bay can be changed in the script. Note that, force unit is in kilo-pound and length is in feet.

### Script

```import numpy as np
import matplotlib.patches as patches
import matplotlib.pyplot as plt

height = 10 # Floor height
storey = 6
bay = 2
bay_widths = np.array([13.125, 13.42])
#force_list = np.array([10, 8.5, 7, 5, 3.5, 2])
bay1_roof = 0.79
bay1_other = 1.4
bay2_roof = 0.799
bay2_other = 1.42
force_list = np.ones((storey,bay))
for i in range(storey):
for j in range(bay):
if i==storey-1 and j==0:
force_list[i,j] = bay1_roof
if i==storey-1 and j==1:
force_list[i,j] = bay2_roof
if i<storey-1 and j==0:
force_list[i,j] = bay1_other
if i<storey-1 and j==1:
force_list[i,j] = bay2_other

bay_widths_cm = np.hstack((0,bay_widths.cumsum()))
heights = height*np.ones(storey)
heights_cm = np.hstack((0,heights.cumsum()))

h_line = storey*bay
v_line = (bay+1)*storey

def frame():
fig= plt.figure(figsize=(10,10))

for i in range(storey):
for j in range(bay):
ax.plot([bay_widths_cm[j],bay_widths_cm[j+1]],[heights_cm[i+1], heights_cm[i+1]], color='blue') #Horizontal line

for i in range(storey):
for j in range(bay+1):
ax.plot([bay_widths_cm[j], bay_widths_cm[j]], [heights_cm[i], heights_cm[i+1]], color='blue')
return fig, ax

fig, ax = frame()
arrow_number=15
for i in range(storey):
arl = 5
for j in range(bay):
ax.text((bay_widths_cm[j]+bay_widths_cm[j+1])/2, heights_cm[i+1]+force_list[i,j]*4 , force_list[i,j])
for k in range(arrow_number):
ax.annotate('', xytext=[bay_widths_cm[j]+(bay_widths[j]/arrow_number)*k,
(force_list[i,j]*4)+heights_cm[i+1]],
xy=[bay_widths_cm[j]+(bay_widths[j]/arrow_number)*k, heights_cm[i+1]],
arrowprops=dict(arrowstyle="->", color='red'),
fontsize=12, size=20)
rect = patches.Rectangle((bay_widths_cm[j],heights_cm[i+1]),
bay_widths[j],(force_list[i,j]*4),linewidth=1,
edgecolor='r',facecolor='green', alpha=0.5)
ax.set_xlim(-bay_widths*0.3, np.max(bay_widths_cm)+bay_widths*0.3)
ax.set_ylim(-height*0.5, (height*storey)+(height*0.5))

def Moment_line(w=0.79, l=13.125):
moment = (w*(0.8*l)**2)/8
#print ('Midspan moment', moment)
sf_ss_end =(w*(0.8*l))/2
end_moment= (sf_ss_end*(0.1*l))+ (w*0.1*l*(0.1*l*0.5))
#print ('Shear:',sf_ss_end)
#print ('End moment:', end_moment)
x = np.linspace(-l/2, l/2, 30)
y = (((-end_moment-moment)/(-l/2)**2)*(x**2))+moment
return x+l/2, y, moment, end_moment, sf_ss_end, sf_ss_end+(w*0.1*l)

# Bending moment diagram for beams
fig_bm, ax_bm = frame()
end_bm = np.ones((storey, bay))
for i in range(storey):
for j in range(bay):
beam_output =Moment_line(w=force_list[i,j], l=bay_widths[j])
x = beam_output
y = beam_output
mid_moment = np.round(beam_output, 2)
end_moment = np.round(beam_output, 2)
end_bm[i,j]=end_moment

ax_bm.fill_between(bay_widths_cm[j]+x, heights_cm[i+1]+(y*0.2),heights_cm[i+1], color='#78c679')
ax_bm.text((bay_widths_cm[j]+bay_widths_cm[j+1])/2, heights_cm[i+1] , mid_moment)
ax_bm.text(bay_widths_cm[j], heights_cm[i+1]-(height*0.35) , end_moment)
ax_bm.text(bay_widths_cm[j+1]-bay_widths[j]*0.15, heights_cm[i+1]-(height*0.35) , end_moment)

ax_bm.set_xlim(-bay_widths*0.3, np.max(bay_widths_cm)+bay_widths*0.3)

# Shear force diagram for beams
fig_bs, ax_bs = frame()
for i in range(storey):
for j in range(bay):
beam_output =Moment_line(w=force_list[i,j], l=bay_widths[j])

end_shear = np.round(beam_output, 2)

ax_bs.fill_between([bay_widths_cm[j], bay_widths_cm[j], bay_widths_cm[j+1], bay_widths_cm[j+1]],
[heights_cm[i+1], heights_cm[i+1]+end_shear*0.5, heights_cm[i+1]-end_shear*0.5, heights_cm[i+1]],
heights_cm[i+1],
color='#78c679')
ax_bs.text((bay_widths_cm[j]+bay_widths_cm[j+1])/2, heights_cm[i+1] , end_shear)

#ax_bm.text(bay_widths_cm[j], heights_cm[i+1]-(height*0.35) , end_moment)
#ax_bm.text(bay_widths_cm[j+1]-bay_widths[j]*0.15, heights_cm[i+1]-(height*0.35) , end_moment)

ax_bs.set_xlim(-bay_widths*0.3, np.max(bay_widths_cm)+bay_widths*0.3)

# Bending moment diagram for columns
end_bm
end_cm = np.ones((storey, bay+1))

end_cm[:,0] = end_bm[:,0][::-1].cumsum()
end_cm[:,-1] = end_bm[:,-1][::-1].cumsum()
end_cm[:,1:-1] = np.reshape(np.diff(end_bm)[::-1].cumsum(), np.shape(end_cm[:,1:-1]))

fig_cm, ax_cm = frame()
for i in range(storey):
for j in range(bay+1):
moment = np.round(end_cm[::-1][i,j],2)
ax_cm.text(bay_widths_cm[j], heights_cm[i]+(height/2) , moment)
scale = .1
ax_cm.fill_betweenx([heights_cm[i], heights_cm[i], heights_cm[i]+height, heights_cm[i]+height],
[bay_widths_cm[j], bay_widths_cm[j]+(moment*scale), bay_widths_cm[j]-(moment*scale), bay_widths_cm[j]],

bay_widths_cm[j],
color='#78c679', interpolate=True)

#ax_cm.set_xlim(-bay_widths*0.5, np.max(bay_widths_cm)+bay_widths*0.5)