OpenSees Cloud
OpenSees AMI
Like Spinning Nodes
Original Post - 19 Sep 2021 - Michael H. Scott
Visit Structural Analysis Is Simple on Substack.
After posting on reasons that the solution to Ax=b fails, I realized I omitted an important case: truss nodes in a frame model. Although this post might be a stretch for an LBU (least bloggable unit), the blogging equivalent of an LPU, there are important factors to consider for structural models comprised of truss and frame elements.
If you define a model with three DOFs per node in 2D or six DOFs per node in 3D in order to mix frame and truss elements, you may end up with DOFs that have no rotational stiffness. Consider the truss-supported beam shown below.
We can define beam elements across the top and truss elements for the vertical and diagonals.
ops.wipe()
ops.model('basic','-ndm',2,'-ndf',3)
ops.node(1,0,0); ops.fix(1,1,1,0)
ops.node(2,50,0)
ops.node(3,100,0); ops.fix(3,1,1,0)
ops.node(4,50,-20)
ops.geomTransf('Linear',1)
ops.element('elasticBeamColumn',1,1,2,...,1)
ops.element('elasticBeamColumn',2,2,3,...,1)
ops.uniaxialMaterial('Elastic',1,E)
ops.element('truss',3,1,4,...,1)
ops.element('truss',4,2,4,...,1)
ops.element('truss',5,3,4,...,1)
Any analysis of this model will fail because the A matrix (stiffness matrix) will be singular. There is no flexural resistance at node 4, i.e., nothing will assemble into the node’s rotational DOF. As a result, the model has a local “spinning node” mechanism at this “truss only” node.
Most solvers in OpenSees will tell you which equation number wreaked havoc. In this case, the ProfileSPD solver indicates that equation number 3 caused problems.
For this simple model, the quick solution is to fix the rotation of node 4.
ops.fix(4,0,0,1)
For larger models, it could be difficult to determine which node is
causing problems. The analyze
command returns a negative number if the
analysis failed, and specifically -3 if the linear equation solver
failed. You can loop through the nodes and output the equation numbers
using the nodeDOFs
command.
ok = ops.analyze(1)
if ok == -3: # Ax=b failed
for nd in ops.getNodeTags():
print(f'Node {nd}: {ops.nodeDOFs(nd)}')
Note that equation numbers are not assigned until you issue the analyze
command, so you cannot get meaningful results from this loop prior to an
analysis.
In addition, many “smart analyze” scripts only check whether analyze
returns 0 (success) or a negative number (failure). So you can burn
through 38 different equilibrium solution algorithms, 42 different time
integrators, and 8 time step subdivisions with no success because the A
matrix was singular in the first place. Check for -3 first.
For the simple beam and truss model, we get the following nodes and equation numbers.
Node 1: [-1, -1, 7]
Node 2: [4, 5, 6]
Node 3: [-1, -1, 0]
Node 4: [1, 2, 3]
Here we see that the problem arises from node 4, whose rotational DOF was assigned equation number 3.
Some software will constrain the rotation of “truss only” nodes automatically, but OpenSees does not. You could write a more elaborate procedure to constrain all spinning nodes; however, it gets a little complicated. You are better off to correct the issue instead of relying on a function to solve the issue for you.
Of course, if you are going to define a model with only truss elements and no beams, declare two DOFs per node in the model builder or three DOFs per node for three-dimensional models.
# 2D
ops.model('basic','-ndm',2,'-ndf',2)
# 3D
ops.model('basic','-ndm',3,'-ndf',3)
With only translational DOFs, none of the nodes will spin.
The title of this post was inspired by Radiohead’s “Like Spinning Plates”. Unlike the song, this post has no underlying social or political meaning.