OpenSees Cloud

OpenSees AMI

No Element Required

Original Post - 14 Jan 2024 - Michael H. Scott

Visit Structural Analysis Is Simple on Substack.


Simulating basic particle motion raises subtle, often overlooked points about OpenSees.

For example, consider problem 12-1 from Hibbeler’s Engineering Mechanics: Dynamics, 14th edition. A particle moves along a straight line with acceleration a=(2t-6) m/s2. What is the velocity at t=6 s and displacement at t=11 s? Assume at rest initial conditions.

By integration, the exact solution for velocity is v=t2-6t m/s and u=t3/3-3t2 m for displacement. At t=6 s, the velocity is v=0 while at t=11 s, the displacement is u=80.67 m.

But how do you solve this incredibly simple problem numerically with OpenSees?

The particle moves along a straight line, so we can define a one-dimensional model with one node for the particle. No boundary conditions required.

We could use multi-support excitation to impose an acceleration history to the node then get the resulting velocity and displacement. But that approach is not very interesting. Instead, we can apply a nodal load history.

Force is mass times acceleration and we can superimpose loads. So, define mass at the node then break the a=(2t-6) m/s2 acceleration function down into linear and constant components, 2t and -6, respectively, using two time series/load pattern combos.

Then run the simulation as a dynamic (transient) analysis. Although not necessary, use a smaller time step (here 0.001 sec) than what you would use in a “normal” dynamic analysis.

import openseespy.opensees as ops

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

mass = 1.0
ops.node(1,0); ops.mass(1,mass)

ops.timeSeries('Constant',1)
ops.pattern('Plain',1,1)
ops.load(1,-6*mass) # F = m*a = -6*m

ops.timeSeries('Linear',2)
ops.pattern('Plain',2,2)
ops.load(1,2*mass) # F = m*a = (2*t)*m

beta = 0.25
ops.integrator('Newmark',0.5,beta)
ops.analysis('Transient','-noWarnings')

dt = 0.001
Tmax = 11
Nsteps = int(Tmax/dt)
for i in range(Nsteps):
   ops.analyze(1,dt)

You can extract and plot the particle velocity and displacement using the nodeVel and nodeDisp commands.

But two things to note from this analysis.

First, there is no element, i.e., no stiffness matrix.

Second, even though there is no stiffness matrix, you can still use the default Newmark integrator and not get a singular matrix in the system of equations. When there is mass but no stiffness or damping matrix, the dynamic tangent for Newmark is \({\bf K}_T={\bf M}/(\beta \Delta t^2)\). You can use the printA function after the analysis to see the dynamic tangent.

ops.system('FullGeneral')
Kdyn = ops.printA('-ret')
print(Kdyn, mass/(beta*dt**2))

Give this analysis a try! See if OpenSees gives the correct values for velocity at t=6 s and displacement at t=11 s.