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.

Truss-supported span

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.

Output from failed solution

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.

Like Spinning Plates