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.