Two Node Link’s Awakening

The twoNodeLink, implemented by Andreas Schellenberg, is one of the lesser utilized general purpose elements in OpenSees. In simple terms, the twoNodeLink element is a zeroLength element with length. And the element is not dis-similar to the link elements you will find in SAP.

Like the zeroLength element, the twoNodeLink element uses uncoupled uniaxial materials to define force-deformation response between two nodes where the deformation is the relative displacement between the nodes.

As far as I can tell, the primary use for twoNodeLink elements in OpenSees has been to define damper elements; however, the twoNodeLink can do so much more than dampers.

But the point of this post is to demonstrate the fundamental similarities and differences between zeroLength and twoNodeLink elements. Consider the simple case of axial loading shown below.

The two elements take the same input: two nodes with an arbitrary number of uniaxial materials acting along or about local axis directions; however, the twoNodeLink element determines its local x-axis from the position vector between the end nodes whereas the zeroLength element requires user input for its local x-axis. In the code below, the local x-axis for the zeroLength element coincides with the global vertical axis.

import openseespy.opensees as ops
from math import isclose

k = 10 # Spring stiffness
P = 5  # Load
L = 10 # Link length

ops.wipe()
ops.model('basic','-ndm',2,'-ndf',3)

ops.node(0,0,0); ops.fix(0,1,1,1)

ops.uniaxialMaterial('Elastic',1,k)

ops.node(1,0,0); ops.fix(1,1,0,1)
ops.element('zeroLength',1,0,1,'-mat',1,'-dir',1,'-orient',0,1,0)

ops.node(2,0,L); ops.fix(2,1,0,1)
ops.element('twoNodeLink',2,0,2,'-mat',1,'-dir',1)

ops.timeSeries('Constant',1)
ops.pattern('Plain',1,1)
ops.load(1,0,P,0)
ops.load(2,0,P,0)

ops.analysis('Static','-noWarnings')
ops.analyze(1)

u1 = ops.nodeDisp(1,2)
u2 = ops.nodeDisp(2,2)

assert isclose(u1,P/k)
assert isclose(u2,P/k)

Even though they have different lengths, the twoNodeLink and zeroLength elements give the same nodal displacement in this case.

The twoNodeLink also handles flexural response, and this is where the element diverges from the zeroLength element. With a moment-rotation spring in a twoNodeLink, a shear distance, or center of rotation, input is required. By default, the center of rotation, c, is half way between the nodes, i.e., c=0.5, but can range anywhere from 0 to 1. In the model below, there are translational and rotational springs in the elements and a lateral load.

The lateral displacement for the zeroLength element will depend only on the translational spring while the lateral displacement with the twoNodeLink element will also have a component that depends on the rotational spring and the location of the center of rotation.

import openseespy.opensees as ops
from math import isclose

kt = 10 # Translational stiffness
kr = 20 # Rotational stiffness
P = 5  # Load
L = 10 # Link length
c = 0.5 # Shear distance

ops.wipe()
ops.model('basic','-ndm',2,'-ndf',3)

ops.node(0,0,0); ops.fix(0,1,1,1)

ops.uniaxialMaterial('Elastic',1,kt)
ops.uniaxialMaterial('Elastic',2,kr)

ops.node(1,0,0); ops.fix(1,0,1,0)
ops.element('zeroLength',1,0,1,'-mat',1,2,'-dir',2,3,'-orient',0,1,0)

ops.node(2,0,L); ops.fix(2,0,1,0)
ops.element('twoNodeLink',2,0,2,'-mat',1,2,'-dir',2,3,'-shearDist',c)

ops.timeSeries('Constant',1)
ops.pattern('Plain',1,1)
ops.load(1,P,0,0)
ops.load(2,P,0,0)

ops.analysis('Static','-noWarnings')
ops.analyze(1)

# X-displacement
u1 = ops.nodeDisp(1,1)
u2 = ops.nodeDisp(2,1)

assert isclose(u1,P/kt)
assert isclose(u2,P/kt + P*L*(1-c)/kr*L*(1-c))

# Rotation
u1 = ops.nodeDisp(1,3)
u2 = ops.nodeDisp(2,3)

assert isclose(u1,0,abs_tol=1e-10)
assert isclose(u2,-P*L*(1-c)/kr)

All four assertions should check out.


The Legend of Zelda reference aside, why does the title of this post imply an awakening of the twoNodeLink element? Well, if instead of uncoupled uniaxial materials we put a section that couples axial, shear, and moment between the two nodes, we have a more efficient and robust implementation of the MVLEM family of elements. All of the constitutive response is handled in the section, e.g., FiberSection and NDFiberSection, not repackaged as a somehow different element formulation in SFI-MVLEM and E-SFI-MVLEM. And we can use the patchlayer, and fiber commands to build wall sections, not confined to areas and reinforcing ratios.

I also suspect we can deal with bond slip models better than the non-sense using zero length section elements and concrete stress blocks that’s been floating around OpenSees for some time now. But I haven’t worked out those details yet.

2 thoughts on “Two Node Link’s Awakening

  1. Good afternoon Professor Scott, greetings from Peru. If I would like to consider the nonlinearity using two-link elements, do you have any example of how to represent this?

    Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.