OpenSees Cloud

OpenSees AMI

It's Not Load Control

Original Post - 07 Feb 2021 - Michael H. Scott

Visit Structural Analysis Is Simple on Substack.


The static integrators in OpenSees, including displacement control, arc length, and minimum unbalanced displacement norm (MUDN), are based on an incremental-iterative framework. After an initial load increment, each integrator imposes a constraint on the change in load factor at subsequent equilibrium iterations within a pseudo-time step.

Displacement control calculates the change in load factor necessary to keep the displacement at a specified DOF constant during iteration. Arc length and MUDN impose other constraints to determine the change in load factor. Load control also fits within this framework, but as a trivial case where the constraint is that the change in load factor is zero.

Although the documentation and many examples would lead you to believe load control controls the load factor, \(\lambda\), you are actually controlling the pseudo-time, t. Here’s the source code to prove it.

Source code for LoadControl

You see variables currentLambda and deltaLambda sprinkled throughout the LoadControl class. But look at lines 127 through 130. These statements are getting, updating, and applying time in the AnalysisModel.

Sure, the time and load factor are the same for the common case of a linear time series where \(\lambda(t)=t\). But, really, load control should be called pseudo-time control.

The point of all this is that imposed displacements via load control is often confused with the displacement control integrator. I mean, what’s clear about the fact that you have to define loads to use displacement control and you have to use load control to impose displacements?

Displacement control is best used when you have a spatial distribution of reference loads that you want to keep in proportion during a pushover analysis, i.e., you want to maintain a vertical distribution of lateral loads. You can control only one degree of freedom (DOF) with displacement control.

Steel frame with displacement control

ops.timeSeries('Linear',2)

ops.pattern('Plain',2,2)
ops.load(3,1.0,0.0,0.0)
ops.load(2,0.5,0.0,0.0)

dU = 0.2
ops.integrator('DisplacementControl',3,1,dU)

To impose displacements at more than one DOF, you need to use sp constraints inside a load pattern. Imposing displacements at multiple locations is not very common in 2D analysis–you’re more likely to see it when imposing bidirectional displacements to 3D models–but it’s shown here anyway for the sake of demonstration.

Steel frame with imposed displacements

The 2.1336 ratio of imposed displacements is based on linear response of the frame for the load pattern used in displacement control.

ops.timeSeries('Linear',2)

dU = 0.2
ops.pattern('Plain',2,2)
ops.sp(3,1,dU)
ops.sp(2,1,dU/2.1336) # Based on linear analysis

ops.integrator('LoadControl',1.0) # Using dt=1.0

Like reference loads, there is no unique way to define imposed reference displacements. So, we could have used 1.0 and 1.0/2.1336 for the sp command along with dU as the time step in the load control integrator.

As expected, the results are quite different because the imposed displacements do not remain proportional to the displacement control load pattern after yield.

Displacement control and imposed displacements

These two approaches give the same result if you control only one DOF.