Parameter Updates in the Loop

Besides visualization and writing output to files, there’s some pretty useful things you can do during an OpenSees analysis. One of those things is updating model parameters.

Before getting into parameter updating, it is worth showing that OpenSees analyses can be run one step at a time. Many examples online show a dynamic analysis, e.g., with 4000 time steps at 0.01 sec, as one analyze command.

Nsteps = 4000
dt = 0.01

ops.analyze(Nsteps, dt)

This approach is perfectly fine, but you can’t do anything during those 4000 steps. So, to get the most out of your analyses and to do stuff as the analysis proceeds, you can equivalently analyze one step at a time, inside a loop.

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

With this as our starting point, let’s look at parameter updating inside the loop.

Consider a two DOF rigid shear frame model. I like to use simple models so that we don’t get mired in the details of the Concrete23 constitutive model and/or the cadillacBeamColumn element formulation.

Let’s suppose, for whatever reason, that the stiffness of the first story reduces linearly to 80% of its initial value during an earthquake of duration T. Not realistic, but it’s a simple demonstration.

{\displaystyle k(t) = k_o\left(1-0.2\frac{t}{T}\right)}

After defining the model, we use the parameter command to identify the stiffness of the first story as a parameter. Each parameter has a tag, which we use to update the parameter inside the analysis loop.

m = 2
k = 100
g = 386.4

import openseespy.opensees as ops

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

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

ops.uniaxialMaterial('Elastic',1,k)

ops.element('zeroLength',1,1,2,'-mat',1,'-dir',1)
ops.element('zeroLength',2,2,3,'-mat',1,'-dir',1)

ops.parameter(1,'element',1,'E')
        
ops.timeSeries('Path',1,'-dt',0.02,'-filePath','tabasFN.txt','-factor',g)
ops.pattern('UniformExcitation',1,1,'-accel',1)
    
ops.analysis('Transient')

T = 50
dt = 0.01
Nsteps = int(T/dt)

for i in range(Nsteps):
    ops.analyze(1,dt)
    ops.reactions()
    t = ops.getTime()
    ops.updateParameter(1,k*(1-0.2*t/T))

Note that each element makes a copy of its material(s). So, even though we’ve defined one elastic uniaxial material, the parameter will be associated with only the copy contained in element 1, i.e., the first story.

Also note that we are passing 'E' to the parameter, not 'k'. The parameter string is based on what the model object, in this case the elastic uniaxial material, understands–not the variable name you used in your script.

The internal methods to identify and update parameters are similar to the methods for creating recorders. So, to see what parameters are valid for your element and material models, search for setParameter in the OpenSees source code just like you would take a look at setResponse to figure out what can be recorded from your elements and materials.

From the analysis, we can see the difference in roof displacement and base shear response history, with and without parameter updates.

Again, this was a very simple example–neither realistic nor meant to imply important engineering results.

As you go out to larger time scales like years, you can examine how your analysis results change as parameters within your model change, e.g., due to corrosion or whatever.

Suppose that the stiffness of the first story reduces to 80% of its initial value after 40 years. We want to know how an earthquake ground motion would affect the structure in each year of this degrading process.

This is a very simple change in parameter updates–in a loop over years, reset the model and update the parameter, then re-run the analysis. This example uses the same ground motion and intensity over all years, but it’s an easy modification to change the intensity or the ground motion.

#
# Using model defined above
#

Nyears = 40

for year in range(Nyears+1):
    ops.reset()
    
    ops.updateParameter(1,k*(1-0.2*year/Nyears))
    
    Umax = 0
    Vmax = 0
    for i in range(Nsteps):
        ops.analyze(1,dt)
        ops.reactions()
        U = ops.nodeDisp(3,1)
        if abs(U) > Umax:
            Umax = abs(U)
        V = ops.nodeReaction(1,1)
        if abs(V) > Vmax:
            Vmax = abs(V)

I don’t like envelope recorders, so I get the maximum responses manually in the inner analysis loop. The maximum roof displacement and base shear over 40 years are shown below.

Even though it’s a linear-elastic model, there is not a direct relationship between the decrease in story stiffness and the peak response quantities. While this outcome was expected, very little additional engineering insight should be inferred from this example.

11 thoughts on “Parameter Updates in the Loop

  1. How can I read the response from the output (which is generated from the recorder) and update that value in each time step ?

    Like

  2. If I need to update parameter ($epsyP) in “uniaxialMaterial ElasticPP $matTag $E $epsyP”. Should I have write my script as

    parameter 1 element $ele_tag epsyP

    and

    updateParameter 1 $Expression_to_recalculate_epsyP_at_each_time_step

    Like

  3. Appreciate for your example. I’m wondering if all the materials in OpenSees have been ready for the sensitivity analysis ? Of course, I’ve known that the key word used in the command can be found in the .cpp source file. However, it is still confusing whether a complicated material like Pinching4 can be available in this regard as well.
    Besides, my modelling is about to update the material properties (or completely replace the material with a new one), e.g. deterioration after fire. What should I do to solve this problem? My point at present is : 1) update the material parameter; 2) remove the element and create new elements after the initial analysis. However, the demo calculation shows that the updated material does not work, and neither does the second method. I’m really looking forward to your comments. Thanks a lot!

    Like

      1. Thanks a lot, professor.
        By the way, I’m wondering if it is possible to update the element domain by removing the original and adding a new element between the related i-j nodes. I’ve found a command named updateElementDomain, but I cannot be assured where it can work out.
        Wish you can given me some hints, thanks again !

        Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

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