OpenSees Cloud

OpenSees AMI

Get the Accel Out

Original Post - 08 Jun 2022 - Michael H. Scott

Visit Structural Analysis Is Simple on Substack.


In OpenSees, a UniformExcitation pattern is functionally equivalent to a regular load pattern, fitting into the framework of a time-varying scalar load factor and constant reference load vector. The scalar load factor is the input ground acceleration, \(\ddot{u}_g(t)\), while the reference load vector is \({\bf P}_{ref}=-{\bf m}{\boldsymbol \iota}\) where \({\bf m}\) is the mass matrix and \({\boldsymbol \iota}\) is the influence vector.

So, if we can get the load factor out of a regular load pattern using the getLoadFactor command, why can’t we get the ground acceleration out of a uniform excitation?

Although the ground acceleration history is a time series input, there are legitimate reasons to extract the ground acceleration from your OpenSees analysis:

  1. You want to make sure the ground acceleration was read correctly, e.g., you might miss a few leading or trailing values when reading records downloaded from ground motion databases;
  2. You want to make sure scale factors were applied correctly to the ground acceleration;
  3. You want to see the interpolated ground acceleration when your analysis time step is not equal to the digitization of the ground acceleration record; or
  4. Similar to 3., you want to see interpolated ground acceleration when your input excitation is an analytic function, e.g., using the Sine (Trigonometric) time series.

Prior to pull request #872, it was not possible to extract the ground acceleration used in a UniformExcitation pattern, at least not directly. Despite some gentle indirection between LoadPattern, GroundMotion, and TimeSeries objects, the implementation of UniformExcitation::getLoadFactor() was easy.

An SDF minimal working example demonstrates the use of getLoadFactor for a uniform excitation.

import openseespy.opensees as ops

ops.wipe()
ops.model('basic','-ndm',1,'-ndf',1)

m = 1.0
Tn = 0.5
wn = 2*3.14159/Tn
k = m*wn**2

ops.node(1,0); ops.fix(1,1)
ops.node(2,0); ops.mass(2,m)

ops.uniaxialMaterial('Elastic',1,k)
ops.element('zeroLength',1,1,2,'-mat',1,'-dir',1)

g = 386.4 # in/sec^2

# Ground motion with 0.02 sec digitization
ops.timeSeries('Path',1,'-dt',0.02,'-filePath','tabasFN.txt','-factor',g,'-prependZero')
ops.pattern('UniformExcitation',23,1,'-accel',1,'-factor',1)

ops.analysis('Transient')

dt = 0.02 # Analysis time step
while ops.getTime() <= 1.0:
    ag = ops.getLoadFactor(23)
    u = ops.nodeDisp(2,1)
    ops.analyze(1,dt)

I showed the -factor option for both the time series and the uniform excitation as you can put the gravitational constant, g, in either command. When doing an incremental dynamic analysis, it makes sense to keep g on the time series and change the scale factor via the uniform excitation pattern. Both of the time series and pattern factors make their way into the output of the getLoadFactor command–play with the factors to see for yourself.

The first second of the ground acceleration and SDF displacement response is shown below with the analysis time step equal to the record digitization (0.02 sec).

Ground motion and response with large time step

Using a smaller analysis time step (0.01 sec) gives the following ground acceleration history and SDF displacement response.

Ground motion and response with smaller time step

Points are linearly interpolated from the input ground acceleration and the displacement response changes slightly, e.g., the maximum displacement over the brief 1 sec analysis changes from 0.09306 inch for the 0.02 sec time step to 0.09431 inch for 0.01 sec.

Now, figuring out how to get the ground acceleration, velocity, and displacement histories out of an OpenSees analysis for multiple support excitation will be more difficult.