OpenSees Cloud
OpenSees AMI
Reinforced Concrete Column Buckling
12 Jun 2026 - Michael H. Scott
Previous posts showed how fiber sections in a corotational mesh of frame elements can simulate the axial load capacity of steel and reinforced concrete columns. This post provides a working script so you can try this type of analysis yourself.
The column model is the same as defined in this post, except the loading is concentric.

A fiber section of Concrete01 and EPP steel is used inside a mesh of
six displacement-based elements. Geometric nonlinearity is initiated
with an L/1000 out-of-straightness.
As shown in the script below, the analysis is performed using displacement control on the vertical displacement of the top node. Alternatively, we can control the horizontal displacement at the column midheight.
import openseespy.opensees as ops
from math import sin,pi
kN = 1.0
mm = 1.0
GPa = kN/mm**2
MPa = 0.001*MPa
# Column dimensions and properties
b = 300*mm
h = b
cover = 40*mm
L = 20*h
Ag = b*h
Abar = 375*mm**2
As = 4*Abar
Ac = Ag-As
fc = 28*MPa
Es = 200*GPa
fy = 420*MPa
# Nominal axial capacity
Pn = fc*Ac + fy*As
Nele = 6
dL = L/Nele
offset = L/1000
ops.wipe()
ops.model('basic','-ndm',2,'-ndf',3)
ops.node(0,0,0); ops.fix(0,1,1,0)
for i in range(Nele):
Y = (i+1)*dL
ops.node(i+1,offset*sin(Y*pi/L),Y)
ops.fix(Nele,1,0,0)
ops.uniaxialMaterial('ElasticPP',1,Es,fy/Es)
ops.uniaxialMaterial('Concrete01',2,fc,0.002,0,0.006)
# Fiber section -- subtract concrete overlapped by r/f steel
ops.section('Fiber',1)
ops.patch('rect',2,20,1,-h/2,-b/2,h/2,b/2)
ops.layer('straight',1,2,Abar,-h/2+cover,-b/2+cover,-h/2+cover,b/2-cover)
ops.layer('straight',1,2,Abar, h/2-cover,-b/2+cover, h/2-cover,b/2-cover)
ops.layer('straight',2,2,-Abar,-h/2+cover,-b/2+cover,-h/2+cover,b/2-cover)
ops.layer('straight',2,2,-Abar, h/2-cover,-b/2+cover, h/2-cover,b/2-cover)
ops.beamIntegration('Legendre',1,1,2)
ops.geomTransf('Corotational',1)
for i in range(Nele):
ops.element('dispBeamColumn',i,i,i+1,1,1)
ops.timeSeries('Linear',1)
ops.pattern('Plain',1,1)
ops.load(Nele,0,-1.0,0) # Reference load
# Target vertical displacement
Umax = 15*mm
Nsteps = 200
dU = Umax/Nsteps
ops.integrator('DisplacementControl',Nele,2,-dU)
ops.system('UmfPack')
ops.test('NormDispIncr',1e-6,10)
ops.analysis('Static','-noWarnings')
for i in range(Nsteps):
ok = ops.analyze(1)
if ok < 0:
break
Plots of the load-displacement response (load vs. vertical displacement at the top of the column and load vs. horizontal displacement at the column midheight) are shown below for both the corotational and the linear geometric transformation.

When using the Linear geometric transformation, there is only material
nonlinearity and the applied load approaches the column axial
capacity–but doesn’t quite get there because of the initial
out-of-straightness.
With the Corotational transformation, buckling initiates at an axial
load of about 2200 kN and displacement control is able to track the
post-peak response.
Try different cross-section sizes, reinforcing details, and material properties, comparing the load-displacement response to the column axial capacity.