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."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.

Discretized frame member

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.