PyJive workshop: Time-dependent analysis#

In this notebook, usage of the ExplicitTimeModule and NewmarkModule for time-dependent analysis of structures is explored. These modules are for solving dynamics problems in the time domain. The first of these is for explicit analysis with the central difference scheme, the second for implicit analysis with Newmark time integration.

In the notebook, we will also use the AccelerationModule for recording accelerations and velocities as additional output to the analysis. There is also an NLNewmarkModule in pyjive for implicit analysis of nonlinear dynamics problems, but we will not use it here.

import numpy as np
import matplotlib.pyplot as plt

import contextlib
import os
from urllib.request import urlretrieve

import sys
pyjivepath = '../../../pyjive/'
sys.path.append(pyjivepath)

if not os.path.isfile(pyjivepath + 'utils/proputils.py'):
    print('\n\n**pyjive cannot be found, adapt "pyjivepath" above or move notebook to appropriate folder**\n\n')
    raise Exception('pyjive not found')

import main
from utils import proputils as pu
from names import GlobNames as gn

%load_ext autoreload
%autoreload 2

%matplotlib widget
**pyjive cannot be found, adapt "pyjivepath" above or move notebook to appropriate folder**
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
Cell In[1], line 14
     12 if not os.path.isfile(pyjivepath + 'utils/proputils.py'):
     13     print('\n\n**pyjive cannot be found, adapt "pyjivepath" above or move notebook to appropriate folder**\n\n')
---> 14     raise Exception('pyjive not found')
     16 import main
     17 from utils import proputils as pu

Exception: pyjive not found
# define a function we will use for plotting force and displacement signals
def plotForceDisp(globdat):
    plt.figure(figsize=(8,3))
    plt.subplot(1,2,1)
    plt.plot(globdat['lodi']['left']['load']['dx'])
    plt.plot(globdat['lodi']['right']['load']['dx'])
    plt.legend(['left','right'])
    plt.ylabel('F')
    plt.xlabel('time step')
    plt.subplot(1,2,2)
    plt.plot(globdat['lodi']['left']['disp']['dx'])
    plt.plot(globdat['lodi']['right']['disp']['dx'])
    plt.legend(['left','right'])
    plt.ylabel('u')
    plt.xlabel('time step')
    plt.show()

# download input files (if necessary)
def findfile(fname):
    url = "https://gitlab.tudelft.nl/cm/public/drive/-/raw/main/transient/" + fname + "?inline=false"
    if not os.path.isfile(fname):
        print(f"Downloading {fname}...")
        urlretrieve(url, fname)

findfile("bar_explicit.pro")
findfile("bar_implicit.pro")
findfile("bar_harmonic.pro")
findfile("bar.geom")
    

Analysis 1: Wave propagation in a bar, explicit#

The first case concerns wave propagation in a bar. It is a bar problem, we have three models that can solve bar problems, the BarModel, the SolidModel, and the FrameModel. We use the last of these for its dedicated postprocessing routines, specifically its option to plot the normal force distribution. We first run the case with the explicit time module.

Task 1: Explicit analysis

Look at the code

  • The ExplicitTimeModule applies central difference scheme. Can you spot a difference with the equation from the lecture where we had \(\hat{\mathbf{M}}\mathbf{a}_{n+1} = \hat{\mathbf{f}}_n\quad\) with \(\quad\hat{\mathbf{M}} = \frac{1}{\Delta t^2}\mathbf{M} + \frac{1}{2\Delta t}\mathbf{C}\quad\) and \(\quad \hat{\mathbf{f}}_n =\frac{1}{\Delta t^2}\mathbf{M}\left(2\mathbf{a}_n-\mathbf{a}_{n-1}\right) + \frac{1}{2\Delta t}\mathbf{C}\mathbf{a}_{n-1} - \mathbf{K}\mathbf{a}_n+\mathbf{f}_n\)? How does this difference affect the functionality?

Look at the input files

  • What are the geometry and boundary conditions?

Run the cell and inspect the results

  • There are no time-dependent boundary conditions, yet this is a dynamics problem. What makes the problem time-dependent?

Investigate stability

  • Change the time step size and rerun. What is the critical time step size for stability?

props = pu.parse_file('bar_explicit.pro')
globdat = main.jive(props)
plotForceDisp(globdat)

Analysis 2: Wave propagation in a bar, implicit#

Another input file is provided for implicit analysis with the NewmarkModule.

Task 2: Implicit analysis

  • Run the cell and inspect the results

  • What happens if you increase the time step size?

  • What happens if you add numerical damping (increase \(\gamma\) adapt \(\beta\) to maintain \(\beta=\gamma/2\))?

  • The behavior in the first time steps is fundamentally different from that in explicit dynamics. What is the numerical source for this?

props = pu.parse_file('bar_implicit.pro')

# run code with output suppressed
print('running pyjive with output suppressed...')
with contextlib.redirect_stdout(open(os.devnull, "w")):
    globdat = main.jive(props)
    
plotForceDisp(globdat)

Analysis 3: Harmonically loaded bar#

Now, instead of a constant load we apply an harmonic load.

Task 3: Harmonic loading

Run the first cell below.

  • Check how time-dependent boundary conditions are applied

  • Inspect the resulting velocity and accelerations

Run the second cell below.

  • What is changed in the case definition?

  • Would it be possible to obtain this result with the ExplicitTimeModule?

props = pu.parse_file('bar_harmonic.pro')

print('running pyjive with output suppressed...')
with contextlib.redirect_stdout(open(os.devnull, "w")):
    globdat = main.jive(props)
plotForceDisp(globdat)

# plot acceleration and velocity at the loaded end
plt.figure()
plt.plot(globdat['acc']['right']['disp']['dx'])
plt.plot(globdat['acc']['right']['velo']['dx'])
plt.plot(globdat['acc']['right']['accel']['dx'])
plt.legend(['disp','velo','accel'])
plt.ylabel('u/v/a')
plt.xlabel('time step')
plt.show()
props = pu.parse_file('bar_harmonic.pro')
props['model']['neum']['deltaTime'] = 1;
props['stepper']['deltaTime'] = 1;
props['model']['neum']['timeSignal']  = 'np.sin(0.01*t)**2'

print('running pyjive with output suppressed...')
with contextlib.redirect_stdout(open(os.devnull, "w")):
    globdat = main.jive(props)
    
plotForceDisp(globdat)