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.sqrt;
import static java.lang.Math.tanh;
import static org.opensha2.gmm.FaultStyle.NORMAL;
import static org.opensha2.gmm.FaultStyle.STRIKE_SLIP;
import static org.opensha2.gmm.FaultStyle.UNKNOWN;
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 static org.opensha2.gmm.Imt.PGA;
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 Campbell (1997) ground motion model for worldwide
* earthquakes in active tectonic regions. In keeping with prior NSHMP
* implementations of this older model, only soft rock sites are supported
* (V𝗌30 = 760 m/s).
*
* <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> Campbell, K.W., 1997, Empirical near-source attenuation
* relationships for horizontal and vertical components of peak ground
* acceleration, peak ground velocity, and pseudo-absolute acceleration response
* spectra, Seismological Research Letters, v. 68, n. 1, pp. 154-179.
*
* <p><b>doi:</b> <a href="http://dx.doi.org/10.1785/gssrl.68.1.154">
* 10.1785/gssrl.68.1.154</a>
*
* <p><b>Errata doi:</b> <a href="http://dx.doi.org/10.1785/gssrl.71.3.352">
* 10.1785/gssrl.71.3.352</a> and <a
* href="http://dx.doi.org/10.1785/gssrl.72.4.474"> 10.1785/gssrl.72.4.474</a>
*
* <p><b>Component:</b> geometric mean of two horizontal
*
* @author Allison Shumway
* @author Peter Powers
* @see Gmm#CAMPBELL_97
*/
public class Campbell_1997 implements GroundMotionModel {
static final String NAME = "Campbell (1997)";
static final Constraints CONSTRAINTS = Constraints.builder()
.set(MW, Range.closed(5.0, 8.0))
.set(RRUP, Range.closed(0.0, 60.0))
.set(RAKE, Faults.RAKE_RANGE)
.set(VS30, Range.singleton(760.0))
.build();
static final CoefficientContainer COEFFS;
static {
COEFFS = new CoefficientContainer("Campbell97.csv");
}
private static final class Coefficients {
final Imt imt;
final double c1, c2, c3, c4, c5, c6, c7, c8, c9, c10;
// unused
// final double c11, c12;
Coefficients(Imt imt, CoefficientContainer cc) {
this.imt = imt;
Map<String, Double> coeffs = cc.get(imt);
c1 = coeffs.get("c1");
c2 = coeffs.get("c2");
c3 = coeffs.get("c3");
c4 = coeffs.get("c4");
c5 = coeffs.get("c5");
c6 = coeffs.get("c6");
c7 = coeffs.get("c7");
c8 = coeffs.get("c8");
c9 = coeffs.get("c9");
c10 = coeffs.get("c10");
}
}
private final Coefficients coeffs;
private final Coefficients coeffsPga;
Campbell_1997(final Imt imt) {
coeffs = new Coefficients(imt, COEFFS);
coeffsPga = new Coefficients(PGA, COEFFS);
}
@Override
public ScalarGroundMotion calc(GmmInput in) {
// distance scaling - per verbal communication with Ken Campbell, it
// is ok to approximate rSeis by constraining rRup to be >= 3.0 km
// (see also Campbell & Bozorgnia 2003)
double rSeis = max(in.rRup, 3.0);
FaultStyle style = GmmUtils.rakeToFaultStyle_NSHMP(in.rake);
double μ = calcMeanPga(coeffsPga, in.Mw, rSeis, style);
double σ = calcStdDevPga(μ);
if (coeffs.imt.isSA()) {
μ = calcMeanSa(coeffs, in.Mw, rSeis, μ);
σ = calcStdDevSa(σ);
}
return DefaultScalarGroundMotion.create(μ, σ);
}
private static final double calcMeanPga(
final Coefficients c,
final double Mw,
final double rSeis,
final FaultStyle style) {
// Implementation is only for soft/generic rock sites so the hard rock
// and soil depth terms have been eliminated
double lnR = log(rSeis);
double f = faultTerm(style);
double rTerm = c.c4 * exp(c.c5 * Mw);
return c.c1 + (c.c2 * Mw) +
c.c3 * log(sqrt(rSeis * rSeis + rTerm * rTerm)) +
(c.c6 + c.c7 * lnR + c.c8 * Mw) * f +
(c.c9 + c.c10 * lnR);
}
private static final double calcMeanSa(
final Coefficients c,
final double Mw,
final double rSeis,
final double μPga) {
return μPga + c.c1 +
c.c2 * tanh(c.c3 * (Mw - 4.7)) +
(c.c4 + (c.c5 * Mw)) * rSeis +
(0.5 * c.c6) +
c.c7 * tanh(c.c8);
}
private static final double calcStdDevPga(final double μPga) {
double pgaLin = exp(μPga);
if (pgaLin < 0.068) {
return 0.55;
} else if (pgaLin <= 0.21) {
return 0.173 - 0.140 * μPga;
} else {
return 0.39;
}
}
private static final double calcStdDevSa(final double σPga) {
return sqrt((σPga * σPga) + (0.27 * 0.27));
}
private static double faultTerm(FaultStyle style) {
return (style == STRIKE_SLIP || style == NORMAL) ? 0.0 : (style == UNKNOWN) ? 0.5 : 1.0;
}
}