package org.opensha2.gmm;
import static java.lang.Math.abs;
import static java.lang.Math.cos;
import static java.lang.Math.cosh;
import static java.lang.Math.exp;
import static java.lang.Math.log;
import static java.lang.Math.max;
import static java.lang.Math.min;
import static java.lang.Math.pow;
import static java.lang.Math.sqrt;
import static java.lang.Math.tanh;
import static org.opensha2.gmm.FaultStyle.NORMAL;
import static org.opensha2.gmm.FaultStyle.REVERSE;
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.VS30;
import static org.opensha2.gmm.GmmInput.Field.Z1P0;
import static org.opensha2.gmm.GmmInput.Field.ZTOP;
import org.opensha2.eq.fault.Faults;
import org.opensha2.gmm.GmmInput.Constraints;
import org.opensha2.util.Maths;
import com.google.common.collect.Range;
import java.util.Map;
/**
* Implementation of the Chiou & Youngs (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><p>Reference: Chiou, B.S.-J. and Youngs R.R., 2008, An NGA model for the
* average horizontal component of peak ground motion and response spectra:
* Earthquake Spectra, v. 24, n. 1, p. 173-215.
*
* <p><b>doi:</b> <a href="http://dx.doi.org/10.1193/1.2894832">
* 10.1193/1.2894832</a>
*
* <p><b>Component:</b> GMRotI50 (geometric mean)
*
* @author Peter Powers
* @see Gmm#CY_08
*/
public final class ChiouYoungs_2008 implements GroundMotionModel {
static final String NAME = "Chiou & Youngs (2008)";
static final Constraints CONSTRAINTS = Constraints.builder()
.set(MW, Range.closed(4.0, 8.5))
.setDistances(200.0)
.set(DIP, Faults.DIP_RANGE)
.set(ZTOP, Range.closed(0.0, 15.0))
.set(RAKE, Faults.RAKE_RANGE)
.set(VS30, Range.closedOpen(150.0, 1500.0))
// TODO borrowed from ASK14
.set(Z1P0, Range.closed(0.0, 3.0))
.build();
static final CoefficientContainer COEFFS = new CoefficientContainer("CY08.csv");
private static final double C2 = 1.06;
private static final double C3 = 3.45;
private static final double C4 = -2.1;
private static final double C4A = -0.5;
private static final double CRB = 50;
private static final double CHM = 3;
private static final double CG3 = 4;
private static final class Coefficients {
final double c1, c1a, c1b, c5, c6, c7, c9, c9a,
cg1, cg2, cn, cm,
φ1, φ2, φ3, φ4, φ5, φ6, φ7, φ8,
τ1, τ2, σ1, σ2, σ3;
// unused
// final double c7a, c10, sig4
Coefficients(Imt imt, CoefficientContainer cc) {
Map<String, Double> coeffs = cc.get(imt);
c1 = coeffs.get("c1");
c1a = coeffs.get("c1a");
c1b = coeffs.get("c1b");
c5 = coeffs.get("c5");
c6 = coeffs.get("c6");
c7 = coeffs.get("c7");
c9 = coeffs.get("c9");
c9a = coeffs.get("c9a");
cg1 = coeffs.get("cg1");
cg2 = coeffs.get("cg2");
cn = coeffs.get("cn");
cm = coeffs.get("cm");
φ1 = coeffs.get("phi1");
φ2 = coeffs.get("phi2");
φ3 = coeffs.get("phi3");
φ4 = coeffs.get("phi4");
φ5 = coeffs.get("phi5");
φ6 = coeffs.get("phi6");
φ7 = coeffs.get("phi7");
φ8 = coeffs.get("phi8");
τ1 = coeffs.get("tau1");
τ2 = coeffs.get("tau2");
σ1 = coeffs.get("sig1");
σ2 = coeffs.get("sig2");
σ3 = coeffs.get("sig3");
}
}
private final Coefficients coeffs;
ChiouYoungs_2008(final Imt imt) {
coeffs = new Coefficients(imt, COEFFS);
}
@Override
public final ScalarGroundMotion calc(final GmmInput in) {
return calc(coeffs, in);
}
private static final ScalarGroundMotion calc(final Coefficients c, final GmmInput in) {
// terms used by both mean and stdDev
double lnYref = calcLnYref(c, in);
double soilNonLin = calcSoilNonLin(c, in.vs30);
double μ = calcMean(c, in.vs30, in.z1p0, soilNonLin, lnYref);
double σ = calcStdDev(c, in.Mw, in.vsInf, soilNonLin, lnYref);
return DefaultScalarGroundMotion.create(μ, σ);
}
// Seismic Source Scaling - aftershock term removed
private static final double calcLnYref(final Coefficients c, final GmmInput in) {
double Mw = in.Mw;
double rJB = in.rJB;
double rRup = in.rRup;
double zTop = in.zTop;
FaultStyle style = GmmUtils.rakeToFaultStyle_NSHMP(in.rake);
double cosDelta = cos(in.dip * Maths.TO_RAD);
double rAlt = sqrt(rJB * rJB + zTop * zTop);
double hw = (in.rX < 0.0) ? 0.0 : 1.0;
double f_term = (style == REVERSE) ? c.c1a : (style == NORMAL) ? c.c1b : 0.0;
return c.c1 + (f_term + c.c7 * (zTop - 4.0)) +
// mainshock term [* (1 - AS)]
// [(c.c10 + c.c7a * (zTop - 4.0)) * AS +] aftershock term
C2 * (Mw - 6.0) + ((C2 - C3) / c.cn) * log(1.0 + exp(c.cn * (c.cm - Mw))) +
C4 * log(rRup + c.c5 * cosh(c.c6 * max(Mw - CHM, 0))) +
(C4A - C4) * 0.5 * log(rRup * rRup + CRB * CRB) +
(c.cg1 + c.cg2 / cosh(max(Mw - CG3, 0.0))) * rRup +
c.c9 * hw * tanh(in.rX * cosDelta * cosDelta / c.c9a) *
(1 - rAlt / (rRup + 0.001));
}
// Mean ground motion model
private static final double calcMean(final Coefficients c, final double vs30,
final double z1p0, final double snl, final double lnYref) {
// basin depth (in meters; z1p0 supplied in km)
double zBasin = Double.isNaN(z1p0) ? calcBasinZ(vs30) : z1p0 * 1000.0;
return lnYref + c.φ1 * min(log(vs30 / 1130.0), 0) +
snl * log((exp(lnYref) + c.φ4) / c.φ4) +
c.φ5 * (1.0 - 1.0 / cosh(c.φ6 * max(0.0, zBasin - c.φ7))) +
c.φ8 / cosh(0.15 * max(0.0, zBasin - 15.0));
}
private static final double calcSoilNonLin(final Coefficients c, final double vs30) {
double exp1 = exp(c.φ3 * (min(vs30, 1130.0) - 360.0));
double exp2 = exp(c.φ3 * (1130.0 - 360.0));
return c.φ2 * (exp1 - exp2);
}
// NSHMP treatment, if vs=760+/-20 -> 40, otherwise compute
private static final double calcBasinZ(final double vs30) {
if (abs(vs30 - 760.0) < 20.0) {
return 40.0;
}
return exp(28.5 - 3.82 * log(pow(vs30, 8.0) + pow(378.7, 8.0)) / 8.0);
}
// Aleatory uncertainty model
private static final double calcStdDev(final Coefficients c, final double Mw,
final boolean vsInf, final double snl, final double lnYref) {
double Yref = exp(lnYref);
// Response Term - linear vs. non-linear
double NL0 = snl * Yref / (Yref + c.φ4);
// Magnitude thresholds
double mTest = min(max(Mw, 5.0), 7.0) - 5.0;
// Inter-event Term
double τ = c.τ1 + (c.τ2 - c.τ1) / 2.0 * mTest;
// Intra-event term (aftershock removed)
double σNL0 = c.σ1 + (c.σ2 - c.σ1) / 2.0 * mTest;
// [+ c.sig4]
double vsTerm = vsInf ? c.σ3 : 0.7;
double NL0sq = (1 + NL0) * (1 + NL0);
σNL0 *= sqrt(vsTerm + NL0sq);
// Total model
return sqrt(τ * τ * NL0sq + σNL0 * σNL0);
}
}