I am confident we can use OpenSees to solve every truss, beam, and frame problem from any statics or structural analysis textbook as well as every single degree-of-freedom and rigid shear frame problem from a structural dynamics textbook. We can also solve any reasonable problem from a finite element textbook.

My confidence starts to wane though for textbook problems from structural mechanics–but you gotta start somewhere. For instance, in Chapter 10 of *Fundamentals of Structural Mechanics*, Hjelmstad shows three examples of bifurcation for idealized single degree-of-freedom systems.

Each model is a rigid column of length *l* with a flexible support of stiffness *k*. Model A has a rotational spring at its base, model B has a translational spring at its free end, and model C is supported by a guy on one side.

To build these models in OpenSees, use a stiff beam-column element with the corotational transformation for large displacements. Then, for models A and B, you can define a zero length element in the appropriate locations along with an initial out of plumb for the column.

```
# Column length and spring stiffness
l = 10
k = 120
# Relatively large E,A,I for column
E = 29000
A = 1000
I = 1e6
ops.wipe()
ops.model('basic','-ndm',2,'-ndf',3)
# Model A
ops.node(1,0,0); ops.fix(1,1,1,0)
ops.node(2,-0.0001*l,l)
ops.node(3,0,0); ops.fix(3,1,1,1)
ops.geomTransf('Corotational',1)
ops.element('elasticBeamColumn',1,1,2,A,E,I,1)
ops.uniaxialMaterial('Elastic',1,k)
ops.element('zeroLength',2,1,3,'-mat',1,'-dir',3)
# Model B
ops.node(1,0,0); ops.fix(1,1,1,0)
ops.node(2,-0.0001*l,l);
ops.node(3,-0.0001*l,l); ops.fix(3,1,0,1)
ops.equalDOF(2,3,2)
ops.geomTransf('Corotational',1)
ops.element('elasticBeamColumn',1,1,2,A,E,I,1)
ops.uniaxialMaterial('Elastic',1,k)
ops.element('zeroLength',2,2,3,'-mat',1,'-dir',1)
```

Due to the finite length of the guy, model C requires a little extra care. You can use a corotational truss element for the guy, but you will have to multiply the material stiffness by the initial length of the guy, i.e, use `k*Lo`

to define the material. Due to asymmetry of the model, you do not need to define an out of plumbness.

```
a = 1.2
Lo = l*(1+a**2)**0.5
# Model C
ops.node(1,0,0); ops.fix(1,1,1,0)
ops.node(2,0,l);
ops.node(3,a*l,0); ops.fix(3,1,1,1)
ops.geomTransf('Corotational',1)
ops.element('elasticBeamColumn',1,1,2,A,E,I,1)
ops.uniaxialMaterial('Elastic',1,k*Lo)
ops.element('corotTruss',2,2,3,1.0,1)
```

The vertical load serves as the reference load for displacement control on the rotation at the base of the column. In each model, this rotation is DOF 3 of node 1.

```
ops.timeSeries('Linear',1)
ops.pattern('Plain',1,1)
ops.load(2,0,-1,0)
Nsteps = 1000
Umax = 3.14 # 3.14/2 for Model A
dU = Umax/Nsteps
# Change to -dU to rotate clockwise
ops.integrator('DisplacementControl',1,3,dU)
```

Rotating the column in both directions, the response of model A is symmetric, stable bifurcation where the column is able to take on more load.

Note that the x-axis is inverted so that the sense of rotation matches the translation of the top of the column, i.e., a positive (counter-clockwise) rotation moves the top of the column to the left. Not a big deal for models A and B, but it’s important for model C.

Model B is also symmetric bifurcation, but the response is unstable because the column must shed load in order to maintain equilibrium.

Model C (using *a*=1.2) shows asymmetric bifurcation. As the column rotates away from the guy, the response is immediately unstable. As the column rotates toward the guy, the response is initially stable until reaching a limit point, then becomes unstable and snaps through.

These models have exact solutions that become intractable for larger systems with flexible columns. So we must use linearizations (eigenvalue analysis) to capture critical buckling loads, as shown in this post.

The title for this post was inspired by a lyric from *Stairway to Heaven*. Go to 09:02 to see Page and Plant reach symmetric bifurcation.