package org.opensha2.gmm; import static java.lang.Math.exp; import static java.lang.Math.log; import static org.opensha2.gmm.FaultStyle.NORMAL; import static org.opensha2.gmm.FaultStyle.REVERSE; import static org.opensha2.gmm.FaultStyle.STRIKE_SLIP; import static org.opensha2.gmm.FaultStyle.UNKNOWN; import static org.opensha2.gmm.GmmInput.Field.DIP; import static org.opensha2.gmm.GmmInput.Field.MW; import static org.opensha2.gmm.GmmInput.Field.RAKE; import static org.opensha2.gmm.GmmInput.Field.RJB; import static org.opensha2.gmm.GmmInput.Field.VS30; import static org.opensha2.gmm.GmmInput.Field.WIDTH; import static org.opensha2.gmm.Imt.PGA; import org.opensha2.eq.Earthquakes; import org.opensha2.eq.fault.Faults; import org.opensha2.gmm.GmmInput.Constraints; import com.google.common.collect.Range; import java.util.Map; /** * Implementation of the Boore & Atkinson (2008) next generation attenuation * relationship for active crustal regions developed as part of <a * href="http://peer.berkeley.edu/ngawest/">NGA West I</a>. * * <p><b>Note:</b> Direct instantiation of {@code GroundMotionModel}s is * prohibited. Use {@link Gmm#instance(Imt)} to retrieve an instance for a * desired {@link Imt}. * * <p><b>Reference:</b> Boore, D.M., and Atkinson, G.M., 2008, Ground-motion * prediction equations for the average horizontal component of PGA, PGV, and * 5%-damped PSA at spectral periods between 0.01s and 10.0s: Earthquake * Spectra, v. 24, n. 1, pp. 99-138. * * <p><b>doi:</b><a href="http://dx.doi.org/10.1193/1.2830434"> * http://dx.doi.org/10.1193/1.2830434</a> * * <p><b>Component:</b> GMRotI50 (geometric mean) * * @author Peter Powers * @see Gmm#BA_08 */ public final class BooreAtkinson_2008 implements GroundMotionModel { static final String NAME = "Boore & Atkinson (2008)"; static final Constraints CONSTRAINTS = Constraints.builder() .set(MW, Range.closed(5.0, 8.0)) .set(RJB, Range.closed(0.0, 200.0)) .set(DIP, Faults.DIP_RANGE) .set(WIDTH, Earthquakes.CRUSTAL_WIDTH_RANGE) .set(RAKE, Faults.RAKE_RANGE) .set(VS30, Range.closedOpen(180.0, 1300.0)) .build(); static final CoefficientContainer COEFFS = new CoefficientContainer("BA08.csv"); private static final double PGAlo = 0.06; private static final double A2 = 0.09; private static final double A1 = 0.03; private static final double V1 = 180.0; private static final double V2 = 300.0; private static final double Vref = 760; private static final double Mref = 4.5; private static final double Rref = 1; static final class Coefficients { final double b_lin, b1, b2, c1, c2, c3, e1, e2, e3, e4, e5, e6, e7, h, mh, s, t_u, s_tu, t_m, s_tm; Coefficients(Imt imt, CoefficientContainer cc) { Map<String, Double> coeffs = cc.get(imt); b_lin = coeffs.get("b_lin"); b1 = coeffs.get("b1"); b2 = coeffs.get("b2"); c1 = coeffs.get("c1"); c2 = coeffs.get("c2"); c3 = coeffs.get("c3"); e1 = coeffs.get("e1"); e2 = coeffs.get("e2"); e3 = coeffs.get("e3"); e4 = coeffs.get("e4"); e5 = coeffs.get("e5"); e6 = coeffs.get("e6"); e7 = coeffs.get("e7"); h = coeffs.get("h"); mh = coeffs.get("mh"); s = coeffs.get("s"); t_u = coeffs.get("t_u"); s_tu = coeffs.get("s_tu"); t_m = coeffs.get("t_m"); s_tm = coeffs.get("s_tm"); } } private final Coefficients coeffs; private final Coefficients coeffsPGA; BooreAtkinson_2008(final Imt imt) { coeffs = new Coefficients(imt, COEFFS); coeffsPGA = new Coefficients(PGA, COEFFS); } @Override public final ScalarGroundMotion calc(final GmmInput in) { return calc(coeffs, coeffsPGA, in); } // TODO not sure how to test this or make backwards compatible version for // comparisons. In 2008, the NSHMP mistakenly would supply fractional // weights // to the different fault styles whereas the 4 different fault styles // should be booleans and only ever have one of their values set to 1. private static final ScalarGroundMotion calc(final Coefficients c, final Coefficients cPGA, final GmmInput in) { FaultStyle style = GmmUtils.rakeToFaultStyle_NSHMP(in.rake); double pga4nl = exp(calcPGA4nl(cPGA, in.Mw, in.rJB, style)); double μ = calcMean(c, style, pga4nl, in); double σ = calcStdDev(c, style); return DefaultScalarGroundMotion.create(μ, σ); } // Mean ground motion model private static final double calcMean(final Coefficients c, final FaultStyle style, final double pga4nl, final GmmInput in) { // Source/Event Term double Fm = calcSourceTerm(c, in.Mw, style); // Path Term double Fd = calcPathTerm(c, in.Mw, in.rJB); // Site Response Term -- Linear double vs30 = in.vs30; double Fs = c.b_lin * log(vs30 / Vref); // Site Response Term -- Nonlinear double bnl = 0.0; // vs30 >= 760 case if (vs30 < Vref) { if (vs30 > V2) { bnl = c.b2 * log(vs30 / Vref) / log(V2 / Vref); } else if (vs30 > V1) { bnl = (c.b1 - c.b2) * log(vs30 / V2) / log(V1 / V2) + c.b2; } else { bnl = c.b1; } } double Fnl = 0.0; if (pga4nl <= A1) { Fnl = bnl * log(PGAlo / 0.1); } else if (pga4nl <= A2) { double dX = log(A2 / A1); double dY = bnl * log(A2 / PGAlo); double _c = (3.0 * dY - bnl * dX) / (dX * dX); double d = -(2.0 * dY - bnl * dX) / (dX * dX * dX); double p = log(pga4nl / A1); Fnl = bnl * log(PGAlo / 0.1) + (_c * p * p) + (d * p * p * p); } else { Fnl = bnl * log(pga4nl / 0.1); } // Total site Fs += Fnl; // Total Model return Fm + Fd + Fs; } // Median PGA for ref rock (Vs30=760m/s); always called with PGA coeffs private static final double calcPGA4nl(final Coefficients c, final double Mw, final double rJB, final FaultStyle style) { // Source/Event Term double Fm = calcSourceTerm(c, Mw, style); // Path Term double Fd = calcPathTerm(c, Mw, rJB); return Fm + Fd; } // Source/Event Term private static final double calcSourceTerm(final Coefficients c, final double Mw, final FaultStyle style) { double Fm = (style == STRIKE_SLIP) ? c.e2 : (style == NORMAL) ? c.e3 : (style == REVERSE) ? c.e4 : c.e1; // else // unkown double MwMh = Mw - c.mh; Fm += (Mw <= c.mh) ? c.e5 * MwMh + c.e6 * MwMh * MwMh : c.e7 * MwMh; return Fm; } // Path Term private static final double calcPathTerm(final Coefficients c, final double Mw, final double rJB) { double r = Math.sqrt(rJB * rJB + c.h * c.h); return (c.c1 + c.c2 * (Mw - Mref)) * log(r / Rref) + c.c3 * (r - Rref); } // Aleatory uncertainty model private static final double calcStdDev(final Coefficients c, final FaultStyle style) { // independent values for tau and sigma are available in coeffs return style == UNKNOWN ? c.s_tu : c.s_tm; } }