Initial Conditions

There are a couple ways to set initial conditions for nodal displacements and velocities in OpenSees. If you look at the end of this post, you’ll see the hard way to do it: set initial displacements as single point (sp) constraints in a load pattern, do one analysis step, then remove the load pattern prior to the response history analysis. You could do the same shenanigans with velocity.

But, when something is that complicated, there should be an easier way–use the setNodeDisp and setNodeVel commands. You just have to be sure to use the '-commit' option with these commands; otherwise, the initial conditions are only trial values that get overwritten on the first analysis step.

Below is a simple script for damped free vibration of an elastic SDF system.

import openseespy.opensees as ops

m = 1 # Mass
c = 0.1*m # Damping

# Period and stiffness
Tn = 2
k = m*(2*3.14159/Tn)**2

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

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

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

# Initial displacement and velocity
u0 = 1
v0 = -5
ops.setNodeDisp(2,1,u0,'-commit')
ops.setNodeVel(2,1,v0,'-commit')

ops.analysis('Transient')

Tf = 10
dt = 0.01
Nsteps = int(Tf/dt)

for i in range(Nsteps):
    ops.analyze(1,dt)

The resulting displacement response history shows the initial conditions are enforced.

You can also use the setNodeAccel command to set initial acceleration for masses subjected to step forces. To automate the calculation of initial acceleration, first apply the force and compute reactions. The reactions command forces OpenSees to compute unbalanced nodal loads–prior to any analysis steps, the unbalance is equal to the applied loads. Finally, compute the initial acceleration using the nodeUnbalance and nodeMass commands, then set the nodal acceleration.

ops.timeSeries('Constant',1)
ops.pattern('Plain',1,1)
ops.load(2,F)

ops.reactions()
a0 = ops.nodeUnbalance(2,1)/ops.nodeMass(2,1)
ops.setNodeAccel(2,1,a0,'-commit')

for i in range(Nsteps):
    ops.analyze(1,dt)

This post focused on an SDF model, but it is straightforward to scale initial conditions up to larger models. Note that the automated calculation of initial acceleration assumes a diagonal mass matrix for the model.


Thanks to Tuan Nguyen for asking about initial accelerations in this post on the OpenSees Facebook group.

5 thoughts on “Initial Conditions

  1. Hi, Michael!

    I wanted to share what I think could be an alternative way of setting the initial acceleration that could account for non-diagonal mass matrices:

    1. Set up your load pattern.

    “`
    ops.timeSeries(‘Constant’,1)
    ops.pattern(‘Plain’,1,1)
    ops.load(2,F)
    “`

    2. Compute the initial acceleration using the A form of Newmark with a very small time step (mathematically, the A form of Newmark allows for dt = 0.0 but the Newmark::newStep() implementation in OpenSees won’t allow it.):

    “`
    ops.integrator(“Newmark”, 0.5, 0.25, “-form”, “A”)
    ops.analysis(“Transient”)
    ops.analyze(1, 1.0e-16) # solve for acceleration at t ~= 0
    ops.wipeAnalysis()
    “`

    3. Continue with your transient analysis:

    “`
    ops.analysis(‘Transient’)
    Tf = 10
    dt = 0.01
    Nsteps = int(Tf/dt)

    for i in range(Nsteps):
    ops.analyze(1,dt)
    “`

    What do you think?

    Liked by 1 person

  2. express my sincere gratitude for your exceptional blog. As an MSc student working extensively with OpenSees, I’ve encountered numerous challenges, and your posts have repeatedly provided clarity and direction. Thank you for your dedication to sharing your knowledge!.

    Liked by 1 person

Leave a reply to Gustavo Araújo Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.