Example 11 : Time series SRA using FDM

Time series analysis to acceleration transfer functions and spectral ratios.

[1]:
import matplotlib.pyplot as plt
import numpy as np

import pystrata

%matplotlib inline
[2]:
# Increased figure sizes
plt.rcParams["figure.dpi"] = 120

Load time series data

[3]:
fname = "data/NIS090.AT2"
with open(fname) as fp:
    next(fp)
    description = next(fp).strip()
    next(fp)
    parts = next(fp).split()
    time_step = float(parts[1])

    accels = [float(part) for line in fp for part in line.split()]

    ts = pystrata.motion.TimeSeriesMotion(fname, description, time_step, accels)
[4]:
ts.accels
[4]:
array([2.33833e-07, 2.99033e-07, 5.15835e-07, ..., 4.90601e-05,
       4.94028e-05, 4.96963e-05], shape=(4096,))

There are a few supported file formats. AT2 files can be loaded as follows:

[5]:
ts = pystrata.motion.TimeSeriesMotion.load_at2_file(fname)
ts.accels
[5]:
array([2.33833e-07, 2.99033e-07, 5.15835e-07, ..., 4.90601e-05,
       4.94028e-05, 4.96963e-05], shape=(4096,))
[6]:
fig, ax = plt.subplots()
ax.plot(ts.times, ts.accels)
ax.set(xlabel="Time (sec)", ylabel="Accel (g)")
fig.tight_layout();
../_images/examples_example-11_8_0.png

Create site profile

This is about the simplest profile that we can create. Linear-elastic soil and rock.

[7]:
profile = pystrata.site.Profile(
    [
        pystrata.site.Layer(
            pystrata.site.DarendeliSoilType(18.0, plas_index=0, ocr=1, stress_mean=200),
            30,
            400,
        ),
        pystrata.site.Layer(pystrata.site.SoilType("Rock", 24.0, None, 0.01), 0, 1200),
    ]
)

Create the site response calculator

[8]:
calcs = [
    ("EQL", pystrata.propagation.EquivalentLinearCalculator()),
    (
        "FDM (KA)",
        pystrata.propagation.FrequencyDependentEqlCalculator(
            strain_ratio=0.65, method="ka02"
        ),
    ),
    (
        "FDM (ZR)",
        pystrata.propagation.FrequencyDependentEqlCalculator(method="zr15"),
    ),
    (
        "FDM (KO 0.3)",
        pystrata.propagation.FrequencyDependentEqlCalculator(method="ko:20"),
    ),
]

Specify the output

[9]:
freqs = np.logspace(-1, np.log10(50.0), num=500)

outputs = pystrata.output.OutputCollection(
    [
        pystrata.output.ResponseSpectrumOutput(
            # Frequency
            freqs,
            # Location of the output
            pystrata.output.OutputLocation("outcrop", index=0),
            # Damping
            0.05,
        ),
        pystrata.output.ResponseSpectrumRatioOutput(
            # Frequency
            freqs,
            # Location in (denominator),
            pystrata.output.OutputLocation("outcrop", index=-1),
            # Location out (numerator)
            pystrata.output.OutputLocation("outcrop", index=0),
            # Damping
            0.05,
        ),
        pystrata.output.AccelTransferFunctionOutput(
            # Frequency
            freqs,
            # Location in (denominator),
            pystrata.output.OutputLocation("outcrop", index=-1),
            # Location out (numerator)
            pystrata.output.OutputLocation("outcrop", index=0),
        ),
        pystrata.output.AccelTransferFunctionOutput(
            # Frequency
            freqs,
            # Location in (denominator),
            pystrata.output.OutputLocation("outcrop", index=-1),
            # Location out (numerator)
            pystrata.output.OutputLocation("outcrop", index=0),
            ko_bandwidth=30,
        ),
    ]
)

Perform the calculation

Compute the response of the site, and store the state within the calculation object, which is then used along with the output collection to compute the desired outputs. Also, extract the computed properties for comparison.

[10]:
properties = {}
for name, calc in calcs:
    calc(ts, profile, profile.location("outcrop", index=-1))
    outputs(calc, name)

    properties[name] = {
        key: getattr(profile[0], key) for key in ["shear_mod_reduc", "damping"]
    }

Plot the final properties

[11]:
for key in properties["EQL"].keys():
    fig, ax = plt.subplots()

    for i, (k, p) in enumerate(properties.items()):
        if k == "EQL":
            ax.axhline(p[key], label=k, color=f"C{i}")
        else:
            ax.plot(ts.freqs, p[key], label=k, color=f"C{i}")

    ax.set(
        ylabel={"damping": "Damping (dec)", "shear_mod_reduc": r"$G/G_{max}$"}[key],
        xlabel="Frequency (Hz)",
        xscale="log",
    )
    ax.legend()
../_images/examples_example-11_19_0.png
../_images/examples_example-11_19_1.png

Plot the outputs

Create a few plots of the output.

[12]:
for output in outputs:
    fig, ax = plt.subplots()
    for name, refs, values in output.iter_results():
        ax.plot(refs, values, label=name)

    ax.set(xlabel=output.xlabel, xscale="log", ylabel=output.ylabel)
    ax.legend()
    fig.tight_layout()
../_images/examples_example-11_21_0.png
../_images/examples_example-11_21_1.png
../_images/examples_example-11_21_2.png
../_images/examples_example-11_21_3.png
[ ]:

[ ]: