pyRotd

PyPI Python Documentation Build Status Code Quality License DOI

Acceleration response spectrum calculations implemented in Python.

Introduction

Simple Python functions for calculating pseudo-spectral acceleration and rotated pseudo-spectral acceleration. The response of the single-degree-of-freedom oscillator is computed in the frequency domain, with frequency-domain interpolation to accurately capture the high-frequency characteristics.

The response spectrum is computed with frequency-domain transfer functions. The motion is interpolated in the frequency domain to ensure that the frequency content extends to at least five times the natural frequency of the oscillator, and it is zero-padded in time so that the free vibration of the oscillator does not wrap around the end of the record. Two perpendicular ground motions can be rotated to compute the response at various percentiles. For example, the minimum, median, and maximum are computed with percentiles of 0, 50, and 100. The orientations of the minimum and maximum are provided, but not those of other percentiles because the rotated spectral acceleration is not monotonically increasing.

Installation

pyRotd requires Python 3.13 or later and is available from the Python Package Index:

python -m pip install pyrotd

How it fits together

pyRotd has two functions that take acceleration time series, and the functions that they are built from.

time_step, accels ────────► calc_spec_accels ───────────► spec_accel at each osc_freq

time_step, accels_a, accels_b ─► calc_rotated_spec_accels ─► spec_accel at each percentile
                                                            (and angle) and osc_freq
  • pyrotd.calc_spec_accels() computes the response of oscillators with natural frequencies osc_freqs and a damping osc_damping to one time series. The result has osc_freq and spec_accel.

  • pyrotd.calc_rotated_spec_accels() takes two perpendicular time series, computes the response of each oscillator to the motion rotated through a range of angles, and returns the percentiles of the rotated responses (by default 0, 50 and 100, which are RotD0, RotD50 and RotD100). The result has osc_freq, percentile, spec_accel and, for the 0th and 100th percentiles, the angle.

  • The response of one oscillator, in the frequency domain, is pyrotd.calc_oscillator_resp(), and for rotations pyrotd.calc_rotated_oscillator_resp(). The peak of a rotated time series (PGA, PGV or PGD) is pyrotd.calc_rotated_peaks().

  • osc_type selects the type of response (the pseudo-spectral acceleration by default), processes the number of processes used to compute the oscillators, and method how the rotated responses are computed.

The time series are in g and the time step is in s. A motion that is not defined by a time series, but by a Fourier amplitude spectrum, has its response spectrum computed by random vibration theory in pyRVT. pyGMM uses pyrotd.calc_oscillator_resp() for the sliding-mass transfer function of Hale and Abrahamson (2019).

Example

#!/usr/bin/env python3
from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np

import pyrotd

pyrotd.processes = 1

# Load the AT2 timeseries
try:
    here = Path(__file__).parent
except NameError:
    # Run by the Sphinx plot directive, which changes into this directory
    here = Path.cwd()
fname = here / "data" / "RSN8883_14383980_13849360.AT2"
with open(fname) as fp:
    for _ in range(3):
        next(fp)
    line = next(fp)
    time_step = float(line[17:25])
    accels = np.array([p for row in fp for p in row.split()]).astype(float)

# Compute the acceleration response spectrum
osc_damping = 0.05
osc_freqs = np.logspace(-1, 2, 91)
resp_spec = pyrotd.calc_spec_accels(time_step, accels, osc_freqs, osc_damping)

# Create a plot!
fig, ax = plt.subplots()

ax.plot(resp_spec.osc_freq, resp_spec.spec_accel)

ax.set(
    xlabel="Frequency (Hz)",
    xscale="log",
    ylabel="5%-Damped Spectral Accel. (g)",
    yscale="log",
)
ax.grid()
fig.tight_layout()
plt.show()

(Source code, png, hires.png, pdf)

_images/example.png

The examples are Jupyter notebooks that are executed by the test suite.

  • Example 1: the response spectrum of one time series.

  • Example 2: the response spectra of two perpendicular time series and the rotated spectra, with the angles of the minimum and the maximum.

API

Response spectra and rotated response spectra from acceleration time series.

pyrotd.calc_oscillator_resp(freq, fourier_amp, osc_damping, osc_freq, max_freq_ratio=5.0, peak_resp_only=False, osc_type='psa')[source]

Compute the time series response of an oscillator.

Parameters:
  • freq (array_like) – frequency of the Fourier acceleration spectrum [Hz]. Should be from an even-length record, e.g., numpy.fft.rfftfreq(n, time_step).

  • fourier_amp (array_like) – Fourier acceleration spectrum [g], as returned by numpy.fft.rfft() (i.e., not scaled by the time step)

  • osc_damping (float) – damping of the oscillator [decimal]

  • osc_freq (float) – frequency of the oscillator [Hz]

  • max_freq_ratio (float, default=5) – minimum required ratio between the oscillator frequency and then maximum frequency of the time series. It is recommended that this value be 5.

  • peak_resp_only (bool, default=False) – If only the peak response is returned.

  • osc_type (str, default='psa') –

    type of response. Options are:

    • ’sd’: spectral displacement (relative to the base)

    • ’sv’: spectral velocity (relative to the base)

    • ’sa’: spectral acceleration (absolute, i.e., relative acceleration plus the input motion)

    • ’psv’: pseudo-spectral velocity

    • ’psa’: pseudo-spectral acceleration

Returns:

response – time series response of the oscillator

Return type:

numpy.ndarray or float

pyrotd.calc_rotated_oscillator_resp(angles, percentiles, freqs, fourier_amps, osc_damping, osc_freq, max_freq_ratio=5.0, osc_type='psa', method='optimized')[source]

Compute the percentiles of response of a rotated oscillator.

Parameters:
  • angles (array_like) – angles to which to compute the rotated time series [deg]

  • percentiles (array_like) – percentiles to return

  • freqs (array_like) – frequency of the Fourier acceleration spectra [Hz]

  • fourier_amps ([array_like, array_like]) – pair of Fourier acceleration spectra [g], as returned by numpy.fft.rfft()

  • osc_damping (float) – damping of the oscillator [decimal]

  • osc_freq (float) – frequency of the oscillator [Hz]

  • max_freq_ratio (float, default=5) – minimum required ratio between the oscillator frequency and then maximum frequency of the time series. It is recommended that this value be 5.

  • osc_type (str, default='psa') – type of response, see calc_oscillator_resp()

  • method (str, default='optimized') – If optimized, then the rotation is done on a subset of values. If rigorous, then all values are considered.

Returns:

response – (osc_freq, percentile, spec_accel, angle) for each percentile

Return type:

list of tuple

pyrotd.calc_rotated_peaks(time_step, accel_a, accel_b, peak_type='pga', percentiles=None, angles=None, method='optimized')[source]

Compute the rotated peak values of input accelerations.

Parameters:
  • time_step (float) – time step of the time series [s]

  • accel_a (array_like) – acceleration time series of the first motion [g]

  • accel_b (array_like) – acceleration time series of the second motion that is perpendicular to the first motion [g]

  • peak_type (str) – Either: pga, pgv, or pgd

  • percentiles (array_like or None) – percentiles to return. Default of [0, 50, 100],

  • angles (array_like or None) – angles to which to compute the rotated time series. Default of np.arange(0, 180, step=1) (i.e., 0, 1, 2, .., 179).

  • method (str, default='optimized') – If optimized, then the rotation is done on a subset of values. If rigorous, then all values are considered.

Returns:

rotated_peak – Records have keys: ‘percentile’, peak_type, and ‘angle’. If pga, then the units are in g. Otherwise, they are reported in cm/s or cm for pgv or pgd, respectively.

Return type:

np.recarray

pyrotd.calc_rotated_percentiles(accels, angles, percentiles=None, method='optimized')[source]

Compute the response spectrum for a time series.

This function computes the period-dependent rotated percentiles. If optimized is True, then the percentiles are only computed at times greater than a threshold. This optimized procedure is described in Equations 2.4 and 2.5 of Stewart et al. (2017) PEER report [1].

Parameters:
  • accels (list of array_like) – pair of acceleration time series

  • angles (array_like) – angles to which to compute the rotated time series

  • percentiles (array_like or None) – percentiles to return

  • method (str, default of optimized) – If optimized, then the rotation is done on a subset of values. If rigorous, then all values are considered.

Returns:

rotated_resp – Percentiles of the rotated response. Records have keys: ‘percentile’, ‘spec_accel’, and ‘angle’.

Return type:

np.recarray

pyrotd.calc_rotated_spec_accels(time_step, accel_a, accel_b, osc_freqs, osc_damping=0.05, percentiles=None, angles=None, max_freq_ratio=5, osc_type='psa', method='optimized', processes=None)[source]

Compute the rotated pseudo-spectral accelerations.

The time series are zero-padded so that the free vibration of the oscillators after the end of the record does not wrap around to the start.

Parameters:
  • time_step (float) – time step of the time series [s]

  • accel_a (array_like) – acceleration time series of the first motion [g]

  • accel_b (array_like) – acceleration time series of the second motion that is perpendicular to the first motion [g]

  • osc_freqs (array_like) – natural frequency of the oscillators [Hz]

  • osc_damping (float) – damping of the oscillator [decimal]. Default of 0.05 (i.e., 5%)

  • percentiles (array_like or None) – percentiles to return. Default of [0, 50, 100],

  • angles (array_like or None) – angles to which to compute the rotated time series. Default of np.arange(0, 180, step=1) (i.e., 0, 1, 2, .., 179).

  • max_freq_ratio (float, default=5) – minimum required ratio between the oscillator frequency and then maximum frequency of the time series. It is recommended that this value be 5.

  • osc_type (str, default='psa') – type of response, see calc_oscillator_resp()

  • method (str, default='optimized') – If optimized, then the rotation is done on a subset of values. If rigorous, then all values are considered.

  • processes (int, optional) – number of processes used to compute the oscillators. Defaults to the module-level processes, which is one (serial).

Returns:

rotated_resp – computed pseudo-spectral acceleration [g] at each of the percentiles. Records have keys: ‘osc_freq’, ‘percentile’, ‘spec_accel’, and ‘angle’

Return type:

np.recarray

pyrotd.calc_spec_accels(time_step, accel_ts, osc_freqs, osc_damping=0.05, max_freq_ratio=5, osc_type='psa', processes=None)[source]

Compute the pseudo-spectral accelerations.

The time series is zero-padded so that the free vibration of the oscillators after the end of the record does not wrap around to the start.

Parameters:
  • time_step (float) – time step of the time series [s]

  • accel_ts (array_like) – acceleration time series [g]

  • osc_freqs (array_like) – natural frequency of the oscillators [Hz]

  • osc_damping (float) – damping of the oscillator [decimal]. Default of 0.05 (i.e., 5%)

  • max_freq_ratio (float, default=5) – minimum required ratio between the oscillator frequency and then maximum frequency of the time series. It is recommended that this value be 5.

  • osc_type (str, default='psa') – type of response, see calc_oscillator_resp()

  • processes (int, optional) – number of processes used to compute the oscillators. Defaults to the module-level processes, which is one (serial).

Returns:

resp_spec – computed pseudo-spectral acceleration [g]. Records have keys: ‘osc_freq’, and ‘spec_accel’

Return type:

np.recarray

pyrotd.processes = 1

Default number of processes used to compute response spectra. The default of one runs serially; a pool is only created when more are requested, either here or with the processes argument.

Development