Source code for pygmm.atkinson_boore_2006
"""Atkinson and Boore (2006, :cite:`atkinson06`) model."""
import numpy as np
from . import model
__author__ = "Albert Kottke"
[docs]
class AtkinsonBoore2006(model.GroundMotionModel):
"""Atkinson and Boore (2006, :cite:`atkinson06`) model.
Developed for the Eastern North America with a reference velocity of 760
or 2000 m/s.
Parameters
----------
scenario : :class:`pygmm.model.Scenario`
earthquake scenario
"""
NAME = "Atkinson and Boore (2006)"
ABBREV = "AB06"
# Load the coefficients for the model
COEFF = dict(
bc=model.load_data_file("atkinson_boore_2006-bc.csv", 2),
rock=model.load_data_file("atkinson_boore_2006-rock.csv", 2),
)
PERIODS = COEFF["bc"]["period"]
COEFF_SITE = model.load_data_file("atkinson_boore_2006-site.csv", 2)
COEFF_SF = model.load_data_file("atkinson_boore_2006-sf.csv", 2)
INDEX_PGD = 0
INDEX_PGV = 1
INDEX_PGA = 2
INDICES_PSA = np.arange(3, 27)
PARAMS = [
model.NumericParameter("mag", True),
model.NumericParameter("dist_rup", True),
model.NumericParameter("v_s30", True),
]
[docs]
def __init__(self, scenario: model.Scenario):
"""Initialize the model."""
super().__init__(scenario)
self._ln_resp = self._calc_ln_resp()
self._ln_std = self._calc_ln_std()
def _calc_ln_resp(self) -> np.ndarray:
"""Calculate the natural logarithm of the response.
Returns
-------
ln_resp : class:`np.array`:
natural log of the response
"""
s = self._scenario
c = self.COEFF["bc"] if s.v_s30 else self.COEFF["rock"]
# Compute the response at the reference condition
r0 = 10.0
r1 = 70.0
r2 = 140.0
f0 = np.maximum(np.log10(r0 / s.dist_rup), 0)
f1 = np.minimum(np.log10(s.dist_rup), np.log10(r1))
f2 = np.maximum(np.log10(s.dist_rup / r2), 0)
# Compute the log10 PSA in units of cm/sec/sec
log10_resp = (
c.c_1
+ c.c_2 * s.mag
+ c.c_3 * s.mag**2
+ (c.c_4 + c.c_5 * s.mag) * f1
+ (c.c_6 + c.c_7 * s.mag) * f2
+ (c.c_8 + c.c_9 * s.mag) * f0
+ c.c_10 * s.dist_rup
)
# Apply stress drop correction
log10_resp += self._calc_stress_factor()
if s.v_s30:
# Compute the site amplification
pga_bc = 10 ** log10_resp[self.INDEX_PGA]
log10_site = self._calc_log10_site(pga_bc)
log10_resp += log10_site
# Convert from cm/sec/sec to gravity
log10_resp -= np.log10(980.665)
ln_resp = np.log(10**log10_resp)
return ln_resp
def _calc_ln_std(self) -> np.ndarray:
"""Calculate the logarithmic standard deviation.
Returns
-------
ln_std : class:`np.array`:
natural log standard deviation
"""
ln_std = np.ones_like(self.PERIODS) * 0.30
return ln_std
def _calc_stress_factor(self) -> float:
"""Calculate the stress correction factor proposed by Atkinson and
Boore (2011) :cite:`atkinson11`.
Returns
-------
log10_stress_factor : class:`np.array`:
log base 10 of the stress factor
"""
s = self._scenario
c = self.COEFF_SF
stress_drop = 10.0 ** (3.45 - 0.2 * s.mag)
v1 = c.delta + 0.05
v2 = 0.05 + c.delta * np.maximum(s.mag - c.m_1, 0) / (c.m_h - c.m_1)
log10_stress_factor = np.minimum(2.0, stress_drop / 140.0) * np.minimum(v1, v2)
return np.interp(self.PERIODS, c.period, log10_stress_factor)
def _calc_log10_site(self, pga_bc: float) -> np.ndarray:
"""Calculate the log10 of the site amplification.
Parameters
----------
pga_bc : float
peak ground acceleration (PGA, g) at the B/C boundary.
Returns
-------
log_10_site : :class:`np.ndarray`
log base 10 of the site amplification.
"""
s = self._scenario
c = self.COEFF_SITE
VS_1 = 180.0
VS_2 = 300.0
VS_REF = 760.0
if s.v_s30 <= VS_1:
b_nl = c.b_1
elif VS_1 < s.v_s30 <= VS_2:
b_nl = (c.b_1 - c.b_2) * np.log(s.v_s30 / VS_2) / np.log(VS_1 / VS_2)
elif VS_2 < s.v_s30 <= VS_REF:
b_nl = c.b_2 * np.log(s.v_s30 / VS_REF) / np.log(VS_2 / VS_REF)
else:
# Vs30 > VS_REF
b_nl = 0
pga_bc = max(pga_bc, 60.0)
log10_site = np.log10(
np.exp(c.b_lin * np.log(s.v_s30 / VS_REF) + b_nl * np.log(pga_bc / 100.0))
)
return np.interp(self.PERIODS, c.period, log10_site)