pyRotd¶
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 frequenciesosc_freqsand a dampingosc_dampingto one time series. The result hasosc_freqandspec_accel.pyrotd.calc_rotated_spec_accels()takes two perpendicular time series, computes the response of each oscillator to the motion rotated through a range ofangles, and returns thepercentilesof the rotated responses (by default 0, 50 and 100, which are RotD0, RotD50 and RotD100). The result hasosc_freq,percentile,spec_acceland, for the 0th and 100th percentiles, theangle.The response of one oscillator, in the frequency domain, is
pyrotd.calc_oscillator_resp(), and for rotationspyrotd.calc_rotated_oscillator_resp(). The peak of a rotated time series (PGA, PGV or PGD) ispyrotd.calc_rotated_peaks().osc_typeselects the type of response (the pseudo-spectral acceleration by default),processesthe number of processes used to compute the oscillators, andmethodhow 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)
The examples are Jupyter notebooks that are executed by the test suite.
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.ndarrayor 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:
- 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.