In [1]:
%config InlineBackend.figure_format = 'svg'

Numerical Integration

Statement of the problem

A single degree of freedom system, with mass m = 500 kg, stiffness k = 72 kN m−1 and damping ratio ζ = 0.05 is at rest when it is subjected to an external force

$\displaystyle p(t) = p_0 \exp\left(-\frac{\omega_n t}{3}\right),$

where $p_0$ = 5.4 kN and $\omega_n ={}$ 12 rad s${}^\text{−1}$ is the undamped natural frequency of the dynamical system.


In [2]:
m = 500.0 ; k = 72000.0 ; z = 0.05 ; p0 = 5400.0 ; wn = 12.0 ; 
c = 2*m*wn*z
wd = wn*sqrt(1.0-z*z)
a = wn/3
def p(t,p0=5400.0): return p0*exp(-a*t)

print 'Damping coefficient: ', c, 'N s/m'


Damping coefficient:  600.0 N s/m

The Exact Response

We can find the exact response for t ≥ 0 using superposition of the general integral and a particular solution.

The Particular Integral

The particular integral for our loading must be $\xi(t)=G\exp(-at)$; substituting in the equation of motion and differentiating we have

$\displaystyle(k-ac+a^2m)\\,G\exp(-at)=p_0\exp(-at)$,

solving for $G$ we have


In [3]:
G = p0/(a*a*m-a*c+k)
print 'Particular integral coefficient: ', G, 'm'


Particular integral coefficient:  0.069587628866 m

The General Integral

The general integral is given by the integral of the homogenous equation plus the particular integral we have just determined:

$\displaystyle x(t)=\exp(-\zeta\omega_nt)\\{A\sin(\omega_dt)+B\cos(\omega_dt)\\}+G\exp(-at)$.

The system starts from initial rest conditions, i.e.,

$\displaystyle x(0) = B+G = 0$,

$\displaystyle \dot x(0) = \omega_dA-\zeta\omega_nB-aG=0$.

Solving the two equations above for B and A gives


In [4]:
B = -G ; A = (a*G+z*wn*B)/wd
print 'Coefficients of the general integral'
print '        A: ', A, 'm'
print '        B: ', B, 'm'


Coefficients of the general integral
        A:  0.0197411867709 m
        B:  -0.069587628866 m

Plotting the exact response

We know the parameters that define the response: we can define a function that returns the value of the response as a function of time and, finally, plot it aside with the particular integral.


In [5]:
def x_ex(t): return exp(-z*wn*t)*(A*sin(wd*t)+B*cos(wd*t))+G*exp(-a*t)
time = linspace(0.0, 3.0, 301)
plot(time,x_ex(time),label=r'$x(t)$',)
plot(time,G*exp(-a*time), label=r'$\xi(t)$')
xlabel('Time, s')
ylabel('Deflections, m')
legend(); grid()


Numerical integration

Integrate the equation of motion in the interval 0 ≤ t ≤ 3 s, using the algorithm of linear acceleration with a time step h = 0.02 s.


In [6]:
h = 0.02
t_stop = 3.0

The linear acceleration algorithm solves the incremental equation of equilibrium where the velocity and acceleration increments, $\Delta v$ and $\Delta a$, are written in terms of the displacement increment $\Delta x$ and the initial conditions $v_0$, $a_0$.

This results in an equation of incremental equilibrium in $\Delta x$, with a modified load increment $\Delta p$ (depending on $v_0$ and $a_0$) and modified stiffness. These are the relevant coefficients:


In [7]:
a0_coef = 3*m + c*h/2
v0_coef = 3*c + 6*m/h
k_m_c  = 3*c/h + 6*m/h/h
k_mod  = k + 3*c/h + 6*m/h/h

We initialize the solution, and also a container for storing the iterates of the solution


In [8]:
container = []
t0 = 0.0 ; p0 = p(t0)
x0 = 0.0 ; v0 = 0.0

Now we propagate the solution


In [9]:
while 1:
    a0 = (p0-c*v0-k*x0)/m
    container.append([t0,p0,x0,v0,a0])
    if t0 > t_stop: break
    t1 = t0 + h
    p1 = p(t1)
    dp = (p1-p0) + v0_coef*v0 + a0_coef*a0
    dx = dp/k_mod
    dv = 3*dx/h - 3*v0 - a0*h/2
    x0 = x0 + dx 
    v0 = v0 + dv
    t0 = t1
    p0 = p1

For simplicity in plotting we put the data collected in our container in a 2D data sructure,


In [10]:
tpxva = array(container)

Now it's time to plot our results

1. The numerical response, 0 < t < 3.0 s
2. A comparison of exact and numerical for 0 < t < 0.3 s
3. Another comparison, at the end of the interval, 2.7 s < t < 3.0 s

In [11]:
plot(tpxva[:,0], tpxva[:,2], label=r'$x(t)$, num.'); grid()
xlabel('Time, s') ; ylabel('Deflections, m')
dummy = axis(xmax=3.0)



In [12]:
plot(time, x_ex(time), label=r'$x(t)$, exact',)
plot(tpxva[:,0], tpxva[:,2], '.b', label=r'$x(t)$, numeric')
xlabel('Time, s') ; ylabel('Deflections, m')
axis(ymin=0.0,xmax=0.30001) ; grid()



In [13]:
plot(time, x_ex(time), label=r'$x(t)$, exact',)
plot(tpxva[:,0], tpxva[:,2], '.b', label=r'$x(t)$, numeric')
xlabel('Time, s') ; ylabel('Deflections, m')
axis(ymin=-0.00, ymax=+0.02, xmin=2.7, xmax=3.0) ; grid()


From the last figure, it is apparent that the numerical procedure, while really accurate in maxima estimation, introduces a slight period elongation in the SDOF system response.

EP Behaviour

Tangent Stiffness and Plastic Deformation

We want to define a function that returns the tangent stiffness and the cumulated plastic deformation as a function of the current displacement and velocity and the cumulated plastic deformation itself.

Such a function depends on the elastic stiffness and the yield force, so here we have a function that defines such a function in terms of k and fy.


In [14]:
def make_kt(k,fy):
    "make_kt(k,fy) returns a function kt(u,v,up) returning kt, up"
    u_y = fy/k
    def kt(u,v,up, uy=u_y):
        f=k*(u-up)
        if (-fy)<f<fy:                return k,up
        if fy<=f    and v>0:  up=u-uy;return 0,up
        if fy<=f    and v<=0: up=u-uy;return k,up
        if f<=(-fy) and v<0:  up=u+uy;return 0,up
        else:                 up=u+uy;return k,up
    return kt

kt = make_kt(k, 6000.0)

Integration with Modified Newton-Raphson

Next we define a function of the current state of the EP oscillator that returns the next state, if there is a stiffness change during the time step the equilibrium is found using a modified Newton-Raphson algorithm.


In [15]:
def step(t0, p0, u0, v0,   a0, k0, up,   fy=6000.0, maxiter=30):
    t1 = t0 + h
    p1 = p(t1)
    Dp = p1 - p0
    Dp_= Dp + v0_coef*v0 + a0_coef*a0
    k_ = k0 + k_m_c
    # we prepare the machinery for the modified Newton-Raphson
    # algorithm.  if we have no state change in the time step, then the
    # N-R algorithm is equivalent to the standard procedure
    u_init=u0; v_init=v0 # initial state
    f_spring=k*(u0-up)   # the force in the spring
    DR=Dp_               # the unbalanced force, initially equal to the
                         # external load increment
    j = 0
    while j < maxiter:
        Du=DR/k_           # the disp increment according to the initial stiffness
        u_next = u_init + Du
        v_next = v_init + 3*Du/h - 3*v_init - a0*h/2
                           # we are interested in the total plastic elongation
        oops,up=kt(u_next,v_next,up)
                           # because we need the spring force at the end
                           # of the time step
        f_spring_next=k*(u_next-up)
                           # so that we can compute the fraction of the
                           # incremental force that's equilibrated at the
                           # end of the time step
        df=f_spring_next-f_spring+(k_-k0)*Du
                           # and finally the incremental forces unbalanced
                           # at the end of the time step
        DR=DR-df
                           # finish updating the system state
        u_init=u_next; v_init=v_next; f_spring=f_spring_next
                           # if the unbalanced load is small enough (the
                           # criteria used in practical programs are
                           # energy based) exit the loop - note that we
                           # have no plasticization/unloading DR==0 at the
                           # end of the first iteration
        if abs(DR)<fy*1E-6 :
            break
        else:
            print "#", t0, j, u_next, DR/fy, up
        j = j+1
    
    # now the load increment is balanced by the spring force and
    # increments in inertial and damping forces, we need to compute the
    # full state at the end of the time step, and to change all
    # denominations to reflect the fact that we are starting a new time step.

    Du=u_init-u0
    Dv=3*Du/h-3*v0-0.5*a0*h
    u1=u0+Du ; v1=v0+Dv
    #print t1, v1, v_init
    return t1, p1, u1, v1

The E-P Integration

For the EP integration we choose a smaller time step, but we have to update all the linear acceleration coefficients that depend on $h$.


In [16]:
h = 0.005
a0_coef = 3*m + c*h/2
v0_coef = 3*c + 6*m/h
k_m_c  = 3*c/h + 6*m/h/h
k_mod  = k + 3*c/h + 6*m/h/h

We initialize the state of the system, note that the quantities that can be computed in terms of the current state are placed inside the execution loop. We initialize also a container where we will store the current state and additional before advancing the solution with a call to the step function


In [17]:
# initialization of the system state and a bit more
t0=0.0 ; p0 = p(t0)
u0=0.0 ; v0 = 0.0; up = 0.0
container = []
# solution loop
while True:
    k0, up = kt(u0, v0, up)
    a0=(p0-c*v0-k*(u0-up))/m
    # print t0, p0, u0, v0, a0, k0, up
    container.append((t0, p0, u0, v0, a0, k0, up))
    if t0 > t_stop: break
    t0, p0, u0, v0 = step( t0, p0, u0, v0,   a0, k0, up)


# 0.18 0 0.0848099916328 0.017719899594 0.0014766582995
# 0.18 1 0.0848108744497 1.0593802069e-05 0.00147754111634
# 0.225 0 0.0910743525592 0.000661155551983 0.00779611552182

Plotting the E-P Response

We put all our data in an array and finally we plot our results. Note that the EP response is quite different from the elastic response, even if the maximum responses are almost identical, because in the EP case we had to put a relatively large permanent deformation in the spring to reach the maximum deflection and this permanent deformation has an evident effect on the (almost, the load is now sooo small...) free response.


In [18]:
tpxvaupkt=array(container)
uy=6000.0/72000.0 ; umax=uy+up
plot( tpxva[:,0], tpxva[:,2], label='EL (num)')
plot( tpxvaupkt[:,0], tpxvaupkt[:,2], label='EP (num)')
plot( (0.1,0.35), (uy,uy), '-k', label=r'$u_y$')
plot( (0.1,0.35), (umax,umax), ':r')
plot( (0.5,3.0), (up,up), ':r', label='$u_p$')
plot( (0.0,3.0), (0,0), '-k')
legend()
axis(xmax=3)
xlabel('Time, s') ; ylabel('Deflections, m')
grid()


Two further plots

Here a plot of the plastic deformation in the neighborhood of the plasticization, next a plot of the deflection in the same time interval.


In [19]:
plot(tpxvaupkt[:,0],tpxvaupkt[:,6],'-k')
plot(tpxvaupkt[:,0],tpxvaupkt[:,6],'.r')
axis(xmin=0.16, xmax=0.30)
xlabel('Time, s') ; ylabel('Cumulated plastic deformation, m')
grid()



In [20]:
plot(tpxvaupkt[:,0],tpxvaupkt[:,2], '-k', label='EP (num)')
plot(tpxva[:,0],tpxva[:,2], '-r', label='EL (num)') 
axis(xmin=0.16,xmax=0.30,ymin=0.00) ; xlabel('Time, s') ; ylabel('Deflections, m'); legend(loc=5) ; grid()