OpenSees Cloud

OpenSees AMI

Daisy Chains and Gaffes

Original Post - 26 Oct 2025 - Michael H. Scott

Show your support at Buy Me a Coffee.


When analyzing rigid bodies with multi-point constraints, one potential problem with the Transformation constraint handler is the sequencing of primary and secondary, or retained and constrained, nodes across multiple constraints.

Using OpenSees to solve Problem 9.39 from J.C. Smith’s Structural Analysis is a perfect opportunity to show how defining constraints in series, i.e., daisy chaining the constraints, can knock you off the path.

Two cables, each with axial stiffness EA=3190 kip (E=29000 ksi, A=0.11 inch2), support a rigid body weighing 20 kip.

You don’t have to define elements for the rigid body. Instead, four nodes (support, center of gravity, and connections to cables) and three rigid beam constraints will represent the rigid body.

With the support node as primary for three rigid beam constraints to secondary nodes at the center of gravity and cable connections, OpenSees sees the model as something like below. Each curved arrow represents a multi-point constraint, pointing from the retained to the constrained node.

The OpenSeesPy script is shown below. Due to the rigid beam constraints, the system has only one DOF, so the solution is straightforward to obtain by hand.

import openseespy.opensees as ops
from math import isclose

kip = 1
ft = 1

inch = ft/12.0

E = 29000*kip/inch**2
A = 0.11*inch**2
W = 20*kip

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

ops.node(1,0,6*ft); ops.fix(1,1,1,1)
ops.node(2,0,0); ops.fix(2,1,1,0)
ops.node(3,5*ft,0)
ops.node(4,6*ft,0)
ops.node(5,10*ft,0)

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

ops.element('truss',1,1,5,A,1)
ops.element('truss',2,1,4,A,1)

ops.rigidLink('-beam',2,3)
ops.rigidLink('-beam',2,4)
ops.rigidLink('-beam',2,5)

ops.timeSeries('Constant',1)
ops.pattern('Plain',1,1)
ops.load(3,0,-W,0)

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

q1 = ops.basicForce(1)[0]
q2 = ops.basicForce(2)[0]

assert isclose(q1,10.05*kip,abs_tol=0.5e-2*kip)
assert isclose(q2,11.39*kip,abs_tol=0.5e-2*kip)

The OpenSees analysis gives the correct answer for the cable forces–10.05 kip and 11.39 kip from the back of the book. However, the support reactions (not shown) are incorrect, but that’s an artifact of the Transformation constraint handler.

Moving on, if we instead define the constraints for the rigid body as a daisy chain from node 2 to 3 to 4 to 5, the OpenSees model would look something like below.

ops.rigidLink('-beam',2,3)
ops.rigidLink('-beam',3,4)
ops.rigidLink('-beam',4,5)

The analysis runs with no problems, but the cable forces are incorrect, and by way more than just a little bit at 41.81 kip and 19.74 kip. Only the order of the constraints changed.

The Penalty and Lagrange constraint handlers will give the correct results for this analysis, but those constraint handlers have their own issues with convergence tests and equation solvers.



Bonus points if you can name the tune that inspired the title of this post.