package org.opensha2.gmm;
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 org.opensha2.gmm.FaultStyle.REVERSE;
import static org.opensha2.gmm.GmmInput.Field.MW;
import static org.opensha2.gmm.GmmInput.Field.RAKE;
import static org.opensha2.gmm.GmmInput.Field.RRUP;
import static org.opensha2.gmm.GmmInput.Field.VS30;
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 ground motion model for shallow crustal earthquakes by
* Sadigh et al. (1997). This implementation supports soil and rock sites, the
* cutoff for which is vs30=750 m/s. This model was also used for subduction
* interface sources in the 2007 Alaska NSHM, for which a custom magnitude
* saturation at M=8.5 was added.
*
* <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> Sadigh, K., Chang, C.-Y. , Egan, J.A., Makdisi, F., and
* Youngs, R.R., 1997, Attenuation relationships for shallow crustal earthquakes
* based on California strong motion data: Seismological Research Letters, v. 6,
* n. 1, p. 180-189.
*
* <p><b>doi:</b> <a href="http://dx.doi.org/10.1785/gssrl.68.1.180">
* 10.1785/gssrl.68.1.180</a>
*
* <p><b>Component:</b> geometric mean of two horizontal components
*
* @author Peter Powers
*/
public class SadighEtAl_1997 implements GroundMotionModel {
/*
* The Sadigh model provides different functional forms for soil and rock site
* classes, has numerous magnitude and style-of-faulting coefficient variants.
* This implementation nests style-of-faulting specific coefficents in the
* coeff tables and keeps four uniform tables for the two site classes
* supported with a low and high magnitude flavor of each. This yields some
* redundancy in the coefficent tables but reduces the need for conditionals.
*/
static final String NAME = "Sadigh et al. (1997)";
static final Constraints CONSTRAINTS = Constraints.builder()
.set(MW, Range.closed(5.0, 8.0))
.set(RRUP, Range.closed(0.0, 100.0))
.set(RAKE, Faults.RAKE_RANGE)
.set(VS30, Range.closed(250.0, 760.0))
.build();
static final CoefficientContainer COEFFS_BC_LO, COEFFS_BC_HI, COEFFS_D_LO, COEFFS_D_HI;
static {
COEFFS_BC_LO = new CoefficientContainer("Sadigh97_BClo.csv");
COEFFS_BC_HI = new CoefficientContainer("Sadigh97_BChi.csv");
COEFFS_D_LO = new CoefficientContainer("Sadigh97_Dlo.csv");
COEFFS_D_HI = new CoefficientContainer("Sadigh97_Dhi.csv");
}
private static final double VS30_CUT = 750.0;
private static final double M_CUT = 8.5;
private static final class Coefficients {
final double c1r, c1ss, c2, c3, c4, c5, c6r, c6ss, c7, σ0, cM, σMax;
Coefficients(Imt imt, CoefficientContainer cc) {
Map<String, Double> coeffs = cc.get(imt);
c1r = coeffs.get("c1r");
c1ss = coeffs.get("c1ss");
c2 = coeffs.get("c2");
c3 = coeffs.get("c3");
c4 = coeffs.get("c4");
c5 = coeffs.get("c5");
c6r = coeffs.get("c6r");
c6ss = coeffs.get("c6ss");
c7 = coeffs.get("c7");
σ0 = coeffs.get("sig0");
cM = coeffs.get("cM");
σMax = coeffs.get("sigMax");
}
}
private final Coefficients coeffs_bc_lo;
private final Coefficients coeffs_bc_hi;
private final Coefficients coeffs_d_lo;
private final Coefficients coeffs_d_hi;
SadighEtAl_1997(final Imt imt) {
coeffs_bc_lo = new Coefficients(imt, COEFFS_BC_LO);
coeffs_bc_hi = new Coefficients(imt, COEFFS_BC_LO);
coeffs_d_lo = new Coefficients(imt, COEFFS_D_LO);
coeffs_d_hi = new Coefficients(imt, COEFFS_D_LO);
}
@Override
public final ScalarGroundMotion calc(final GmmInput in) {
FaultStyle faultStyle = GmmUtils.rakeToFaultStyle_NSHMP(in.rake);
double μ, σ;
/* Modified to saturate above Mw=8.5 */
double Mw = min(in.Mw, 8.5);
if (in.vs30 > VS30_CUT) {
/* Rock */
Coefficients c = Mw <= 6.5 ? coeffs_bc_lo : coeffs_bc_hi;
μ = calcRockMean(c, Mw, in.rRup, faultStyle);
σ = calcStdDev(c, Mw);
} else {
/* Soil */
Coefficients c = Mw <= 6.5 ? coeffs_d_lo : coeffs_d_hi;
μ = calcSoilMean(c, Mw, in.rRup, faultStyle);
σ = calcStdDev(c, Mw);
}
return DefaultScalarGroundMotion.create(μ, σ);
}
private static final double calcRockMean(final Coefficients c, final double Mw,
final double rRup, final FaultStyle style) {
/*
* Rock site coeffs are not dependent on style-of-faulting so we just use
* the rock flavor (c1r == c1ss)
*/
double lnY =
c.c1r +
c.c2 * Mw +
c.c3 * pow(M_CUT - Mw, 2.5) +
c.c4 * log(rRup + exp(c.c5 + c.c6r * Mw)) +
c.c7 * log(rRup + 2);
/* Scale reverse amplitudes by 1.2; 0.18232 = ln(1.2) */
return (style == REVERSE) ? lnY + 0.18232 : lnY;
}
private static final double calcSoilMean(final Coefficients c, final double Mw,
final double rRup, final FaultStyle style) {
double c1 = (style == REVERSE) ? c.c1r : c.c1ss;
double c6 = (style == REVERSE) ? c.c6r : c.c6ss;
return c1 +
c.c2 * Mw -
c.c3 * log(rRup + c.c4 * exp(c.c5 * Mw)) +
c6 +
c.c7 * pow(M_CUT - Mw, 2.5);
}
private static final double calcStdDev(final Coefficients c, final double Mw) {
/*
* mMax_bc = 7.21, mMax_d = 7.0, coeff tables were populated with maxSigma
* for soil sites, maxSigma for rock were included in publication
*/
return max(c.σ0 + c.cM * Mw, c.σMax);
}
}