OpenSees Cloud
OpenSees AMI
Discretized Members Only
Original Post - 02 Jun 2021 - Michael H. Scott
Visit Structural Analysis Is Simple on Substack.
I wrote a DiscretizeMember
procedure in Tcl many years ago–I don’t
know exactly when, definitely after the 1980s and definitely
before moving to
Eastchester.
"Members Only." by The Semi-Frozen Trombone is licensed under CC BY 2.0
After carrying the function around for years, and probably spawning more variations than uniaxial Concrete models, the procedure went in to svn (now in GitHub) in 2014 as part of a reliability example. Even there, it’s buried and hard to find.
Then, along came OpenSeesPy. One of the cool things about the
OpenSees Python package (pip) is you can include helper functions
and entire modules written in native Python. For example, there
are a couple of very nice post-processing libraries, Get_Rendering
and ops_vis
.
With a little bit (meaning, a lot) of help from Minjie, I added a
Python version of the DiscretizeMember
function to a
pre-processing library in OpenSeesPy.
The Python version is basically the same as the Tcl version, but with some minor differences to handle beam integration objects and the input and output of node and element tags. The function inputs are shown below.
def DiscretizeMember(ndI,ndJ,numEle,eleType,integrTag,transfTag,nodeTag,eleTag):
Elements are created between ndI
and ndJ
. All numEle
elements have
the same eleType
, which can be 'forceBeamColumn'
,
'dispBeamColumn'
, or others, and the same beam integration tag
(integrTag
) and geometric transformation tag (transfTag
). The
function works for 3D models where all discretized elements for a
member should have the same
vector in the x-z plane.
The inputs nodeTag
and eleTag
tell the function where to start
numbering the internal nodes and elements from ndI
to ndJ
.
The function returns two lists: one of the element tags created and the other of the node tags created. These lists are useful if you need to circle back and add loads along the member.
Below is an example for the frame model from this post.
import openseespy.opensees as ops
import openseespy.preprocessing.DiscretizeMember as dm
H = 360
L = 144
ops.wipe()
ops.model('basic','-ndm',2,'-ndf',3)
ops.node(1,0,0); ops.fix(1,1,1,1)
ops.node(2,0,L)
ops.node(3,H,L)
ops.node(4,H,0); ops.fix(4,1,1,1)
E = 29000
# W14x90
ops.section('Elastic',1,E,26.5,999)
ops.beamIntegration('Legendre',1,1,2)
# W18x76
ops.section('Elastic',2,E,22.3,1330)
ops.beamIntegration('Legendre',2,2,2)
# Corotational transformation
ops.geomTransf('Corotational',1)
# Number of elements/member
Nele = 8
# Columns
dm.DiscretizeMember(1,2,Nele,'dispBeamColumn',1,1,10,10)
dm.DiscretizeMember(3,4,Nele,'dispBeamColumn',1,1,30,30)
# Beam - storing and printing the return values for demonstration
elems,nodes = dm.DiscretizeMember(2,3,Nele,'dispBeamColumn',2,1,50,20)
print(f'Beam nodes: {nodes}')
print(f'Beam elements: {elems}')
Give the code a try. You should see the lists of node and element tags created for the beam member.