From time to time, I dabble with the OpenSees warping elements developed at the University of Sydney in 2011 for doubly symmetric sections, then in 2016 for open sections.
Since my last foray into warping, I’ve taken the nonlinear displacement-based formulation from “it compiles” to “it works”. Some other ancillary changes to the warping fiber section were required, but that’s a detail for another day.
Torsional buckling of a W-shape column is one of the examples presented by the Sydney group. The column is subjected to an increasing axial load, P, after introducing twist by imposing a small torsional moment (485 N-mm) at mid-height. The torsional moment is held constant as the axial load increases.

The ends of the column are restrained against transverse motion and twist, but allowed to warp. Vertical displacement is restrained at column mid-height. The column is discretized into multiple elements with corotational transformation (the only option for the warping elements) and the section is discretized into 32 fibers through the web and 32 fibers in each flange with only one fiber through the thickness of each section element. The material response is linear-elastic.
import openseespy.opensees as ops
# Units = N,mm
d = 100
tw = 3
bf = 75
tf = 3
J = 2223
E = 2.0e5
v = 0.3
G = 0.5*E/(1+v)
L = 6000
Nele = 4
dL = L/Nele
ops.wipe()
ops.model('basic','-ndm',3,'-ndf',7)
ops.uniaxialMaterial('Elastic',1,E)
ops.section('WFSection2d',1,1,d,tw,bf,tf,32,1,32,1,'-warping','-GJ',G*J)
Np = 3
ops.beamIntegration('Legendre',1,1,Np)
ops.geomTransf('Corotational',1,0,0,1)
ops.node(0,0,0,0)
ops.fix(0, 1,0,1,0,1,0,0)
for i in range(Nele):
ops.node(i+1,0,(i+1)*dL,0)
ops.element('dispBeamColumnWarping',i+1,i,i+1,1,1)
ops.fix(Nele, 1,0,1,0,1,0,0)
# Vertical restraint at middle node
ops.fix(Nele//2, 0,1,0,0,0,0,0)
# Apply torsional moment
ops.timeSeries('Constant',1)
ops.pattern('Plain',1,1)
ops.load(Nele//2, 0,0,0,0,485,0,0)
ops.system('UmfPack')
ops.integrator('LoadControl',0)
ops.test('NormDispIncr',1e-6,10,0)
ops.algorithm('Newton')
ops.analysis('Static','-noWarnings')
ops.analyze(1)
# Axial load
ops.timeSeries('Linear',2)
ops.pattern('Plain',2,2)
ops.load(0, 0,1,0,0,0,0,0)
ops.load(Nele, 0,-1,0,0,0,0,0)
Pmax = 200e3
Nsteps = 1000
dP = Pmax/Nsteps
ops.integrator('LoadControl',dP)
ops.analyze(Nsteps)
The computed relationship between axial load and twist angle at mid-height of the column is shown below for increasing number of elements.

As described in the 2016 report, the theoretical buckling load is P=98 kN. The post-buckling response converges with 10 elements and matches an Abaqus analysis with 3600 S8R shell elements (also described in the report). The final twist angle is 3.67 radians, or about 210 degrees!

Cool post. I have several questions:
Why does WFSection2d work for a 3d analysis?
Why doesn’t the column buckle flexurally about the minor axis first?
Would torsional buckling happen using the regular dispBeamColumn element? If yes, at what load?
LikeLiked by 1 person
Thanks, Mark!
Good question on the WFSection2d. I added some arguments, but should have also changed the command name.
The couple moment is enough to trigger torsional buckling or prevent flexural buckling.
The regular dispBeamColumn will not buckle torsionally, unless perhaps the corotational mesh is very fine. Would be a good test!
LikeLike
Thank you, Professor, for the insightful post! I was wondering if you have also checked the mid-span out-of-plane displacement. I’ve attempted to plot the response for each degree of freedom but have not been able to replicate the results from the 2016 report.
LikeLike