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.

I am guessing that when you say “However, the support reactions (not shown) are incorrect, but that’s an artifact of the
Transformationconstraint handler.”, there is no easy fix for it. The Transformation handler is fickle.LikeLike
I don’t think the Transformation constraint handler is fickle. It’s doing what it’s supposed to do. The reactions are all wonky because the secondary nodes become constrained and develop their own reactions even though there is no external support. The sum of global forces is still correct if you sum reactions over all nodes in the model.
LikeLike
Interesting. I wouldn’t have thought to look for the reactions at the constrained nodes.
LikeLike
Although, now that I wrote “at the constrained nodes”, it makes sense that they would have reactions.
LikeLike
I’ve burned myself too many times on this, learned the hard way!
LikeLiked by 1 person