package org.opensha2.gmm;
import static java.lang.Math.exp;
import static java.lang.Math.log;
import static java.lang.Math.min;
import static java.lang.Math.sqrt;
import static org.opensha2.gmm.GmmInput.Field.MW;
import static org.opensha2.gmm.GmmInput.Field.RRUP;
import static org.opensha2.gmm.GmmInput.Field.VS30;
import static org.opensha2.gmm.GmmInput.Field.ZTOP;
import org.opensha2.eq.Earthquakes;
import org.opensha2.gmm.GmmInput.Constraints;
import com.google.common.collect.Range;
import java.util.Map;
/**
* Abstract implementation of the subduction ground motion model by Zhao et al.
* (2006). This implementation matches that used in the USGS NSHM.
*
* <p>This model supports both slab and interface type events. In the 2008
* NSHMP, the 'interface' form is used with the Cascadia subduction zone models
* and the 'slab' form is used with gridded 'deep' events in northern California
* and the Pacific Northwest.
*
* <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>Implementation notes:</b> <ol><li>When used for interface events, sigma
* is computed using the generic value of tau, rather than the interface
* specific value (see inline comments for more information).<li><li>Hypocentral
* depths for interface events are fixed at 20km.</li><li>Hypocentral depths for
* slab events are set to {@code min(zTop, 125)}; minimum rupture distance
* (rRup) is 1.0 km.</li></ol>
*
* <p><b>Reference:</b> Zhao, J.X., Zhang, J., Asano, A., Ohno, Y., Oouchi, T.,
* Takahashi, T., Ogawa, H., Irikura, K., Thio, H.K., Somerville, P.G.,
* Fukushima, Y., and Fukushima, Y., 2006, Attenuation relations of strong
* ground motion in Japan using site classification based on predominant period:
* Bulletin of the Seismological Society of America, v. 96, p. 898–913.
*
* <p><b>doi:</b> <a href="http://dx.doi.org/10.1785/0120050122">
* 10.1785/0120050122</a>
*
* <p><b>Component:</b> Geometric mean of two horizontal components
*
* @author Peter Powers
* @see Gmm#ZHAO_06_INTER
* @see Gmm#ZHAO_06_SLAB
*/
public abstract class ZhaoEtAl_2006 implements GroundMotionModel {
static final String NAME = "Zhao et al. (2006)";
// TODO will probably want to have constraints per-implementation
static final Constraints CONSTRAINTS = Constraints.builder()
.set(MW, Range.closed(5.0, 9.5))
.set(RRUP, Range.closed(0.0, 1000.0))
.set(ZTOP, Earthquakes.SLAB_DEPTH_RANGE)
.set(VS30, Range.closed(150.0, 1000.0))
.build();
static final CoefficientContainer COEFFS = new CoefficientContainer("Zhao06.csv");
private static final double HC = 15.0;
private static final double MC_S = 6.5;
private static final double MC_I = 6.3;
private static final double GCOR = 6.88806;
private static final double MAX_SLAB_DEPTH = 125.0;
private static final double INTERFACE_DEPTH = 20.0;
private static final class Coefficients {
final double a, b, c, d, e, Si, Ss, Ssl, C1, C2, C3, σ, τ, τS, Ps, Qi, Qs, Wi, Ws;
// unused
// final double Sr, tauI;
Coefficients(Imt imt, CoefficientContainer cc) {
Map<String, Double> coeffs = cc.get(imt);
a = coeffs.get("a");
b = coeffs.get("b");
c = coeffs.get("c");
d = coeffs.get("d");
e = coeffs.get("e");
Si = coeffs.get("Si");
Ss = coeffs.get("Ss");
Ssl = coeffs.get("Ssl");
C1 = coeffs.get("C1");
C2 = coeffs.get("C2");
C3 = coeffs.get("C3");
σ = coeffs.get("sigma");
τ = coeffs.get("tau");
τS = coeffs.get("tauS");
Ps = coeffs.get("Ps");
Qi = coeffs.get("Qi");
Qs = coeffs.get("Qs");
Wi = coeffs.get("Wi");
Ws = coeffs.get("Ws");
}
}
private final Coefficients coeffs;
ZhaoEtAl_2006(final Imt imt) {
coeffs = new Coefficients(imt, COEFFS);
}
@Override
public final ScalarGroundMotion calc(GmmInput in) {
double μ = calcMean(coeffs, isSlab(), in);
double σ = calcStdDev(coeffs, isSlab());
return DefaultScalarGroundMotion.create(μ, σ);
}
abstract boolean isSlab();
private static final double calcMean(final Coefficients c, final boolean slab,
final GmmInput in) {
double Mw = in.Mw;
double rRup = Math.max(in.rRup, 1.0); // avoid ln(0) below
double zTop = slab ? min(in.zTop, MAX_SLAB_DEPTH) : INTERFACE_DEPTH;
double vs30 = in.vs30;
double site = (vs30 >= 600.0) ? c.C1 : (vs30 >= 300.0) ? c.C2 : c.C3;
double hfac = (zTop < HC) ? 0.0 : zTop - HC;
double m2 = Mw - (slab ? MC_S : MC_I);
double afac, xmcor;
if (slab) {
afac = c.Ssl * log(rRup) + c.Ss;
xmcor = c.Ps * m2 + c.Qs * m2 * m2 + c.Ws;
} else {
afac = c.Si;
xmcor = c.Qi * m2 * m2 + c.Wi;
}
double r = rRup + c.c * exp(c.d * Mw);
double gnd = c.a * Mw + c.b * rRup - Math.log(r) + site;
gnd = gnd + c.e * hfac + afac;
return gnd + xmcor - GCOR;
}
private static final double calcStdDev(final Coefficients c, final boolean slab) {
// Frankel email may 22 2007: use sigt from table 5. Not the
// reduced-tau sigma associated with mag correction seen in
// table 6. Zhao says "truth" is somewhere in between.
return sqrt(c.σ * c.σ + (slab ? c.τS * c.τS : c.τ * c.τ));
}
static final class Interface extends ZhaoEtAl_2006 {
static final String NAME = ZhaoEtAl_2006.NAME + ": Interface";
Interface(Imt imt) {
super(imt);
}
@Override
final boolean isSlab() {
return false;
}
}
static final class Slab extends ZhaoEtAl_2006 {
static final String NAME = ZhaoEtAl_2006.NAME + ": Slab";
Slab(Imt imt) {
super(imt);
}
@Override
final boolean isSlab() {
return true;
}
}
}