package org.opensha2.eq; import static org.opensha2.data.Data.checkInRange; import com.google.common.collect.Range; /** * Constants and utility methods pertaining to properties of earthquakes. * * <p><strong>Note:</strong> The various fields and methods of this class that * relate to earthquake depths follow the positive-down convention of * seismology. * * @author Peter Powers */ public final class Earthquakes { private Earthquakes() {} /* * TODO possibly adjust Faults.CRUSTAL_DEPTH_RANGE CB14 restricts to 20 km and * the PEER database is pretty comprehensive. Perhaps implement active and * stable crust depth range. */ /** Supported earthquake depths: {@code [-5..700] km}. */ public static final Range<Double> DEPTH_RANGE = Range.closed(-5.0, 700.0); /** Supported crustal earthquake depths: {@code [0..40] km}. */ public static final Range<Double> CRUSTAL_DEPTH_RANGE = Range.closed(0.0, 40.0); /** Supported crustal earthquake widths: {@code [0..60] km}. */ public static final Range<Double> CRUSTAL_WIDTH_RANGE = Range.openClosed(0.0, 60.0); /** Supported subduction interface earthquake depths: {@code [0..60] km}. */ public static final Range<Double> INTERFACE_DEPTH_RANGE = Range.closed(0.0, 60.0); /** Supported subduction interface earthquake widths: {@code [0..200] km}. */ public static final Range<Double> INTERFACE_WIDTH_RANGE = Range.openClosed(0.0, 200.0); /** Supported subduction intraslab earthquake depths: {@code [20..700] km}. */ public static final Range<Double> SLAB_DEPTH_RANGE = Range.closed(20.0, 700.0); /** * Supported earthquake magnitudes: {@code [-2.0..9.7]}. This range of * values is not bound to any particular magnitude scale. */ public static final Range<Double> MAG_RANGE = Range.closed(-2.0, 9.7); /** Shear modulus {@code μ = 3·10¹⁰ N·m⁻²}. */ public static final double MU = 3e10; private static final double SCALE_N_M = 9.05; /* * Equivalent dyn/cm values for MU = 3e11 dyn/cm² * * Equivalent dyn/cm values for SCALE_ = 16.05 dyn·cm */ /** * Ensure {@code -5 ≤ depth ≤ 700 km}. * * @param depth to validate * @return the validated depth * @throws IllegalArgumentException if {@code depth} is outside the range * {@code [-5..700] km} */ public static double checkDepth(double depth) { return checkInRange(DEPTH_RANGE, "Depth", depth); } /** * Ensure {@code 0 ≤ depth ≤ 40 km}. * * @param depth to validate * @return the validated depth for use inline * @throws IllegalArgumentException if {@code depth} is outside the range * {@code [0..40] km} */ public static double checkCrustalDepth(double depth) { return checkInRange(CRUSTAL_DEPTH_RANGE, "Depth", depth); } /** * Ensure {@code 0 ≤ width ≤ 60 km}. * * @param width to validate * @return the validated width * @throws IllegalArgumentException if {@code width} is outside the range * {@code [0..60] km} */ public static double checkCrustalWidth(double width) { return checkInRange(CRUSTAL_WIDTH_RANGE, "Width", width); } /** * Ensure {@code 0 ≤ depth ≤ 60 km}. * * @param depth to validate * @return the validated depth * @throws IllegalArgumentException if {@code depth} is outside the range * {@code [0..60] km} */ public static double checkInterfaceDepth(double depth) { return checkInRange(INTERFACE_DEPTH_RANGE, "Subduction Interface Depth", depth); } /** * Ensure {@code 0 ≤ width ≤ 200 km}. * * @param width to validate * @return the validated width * @throws IllegalArgumentException if {@code width} is outside the range * {@code [0..200] km} */ public static double checkInterfaceWidth(double width) { return checkInRange(INTERFACE_WIDTH_RANGE, "Subduction Interface Width", width); } /** * Ensure {@code 20 ≤ depth ≤ 700 km}. * * @param depth to validate * @return the validated depth * @throws IllegalArgumentException if {@code depth} is outside the range * {@code [20..700] km} */ public static double checkSlabDepth(double depth) { return checkInRange(SLAB_DEPTH_RANGE, "Subduction Slab Depth", depth); } /** * Ensure {@code -2.0 ≤ magnitude ≤ 9.7}. * * @param magnitude to validate * @return the validated magnitude * @throws IllegalArgumentException if {@code magnitude} value is outside the * range {@code [-2.0..9.7]} */ public static double checkMagnitude(double magnitude) { return checkInRange(MAG_RANGE, "Magnitude", magnitude); } /** * Convert moment magnitude, <em>M</em><sub>W</sub>, to seismic moment, * <em>M</em>₀, following the equation of Hanks and Kanamori (1997). * * @param magnitude to convert * @return the equivalent seismic moment in N·m */ public static double magToMoment(double magnitude) { return Math.pow(10, 1.5 * magnitude + SCALE_N_M); } /** * Convert seismic moment, <em>M</em>₀, to moment magnitude, * <em>M</em><sub>w</sub>, following the equation of Hanks and Kanamori * (1997). * * @param moment to convert (in N·m) * @return the equivalent moment magnitude */ public static double momentToMag(double moment) { return (Math.log10(moment) - SCALE_N_M) / 1.5; } /** * Calculate (in SI units) the seismic moment of a fault area and average * slip, assuming a shear modulus of {@link #MU}. If slip <em>rate</em> is * supplied, moment <em>rate</em> is returned. * * @param area in m² * @param slip in m (or slip rate in m·t⁻¹) * @return moment (<em>M</em>₀) in N·m (or moment rate in N·m·t⁻¹) */ public static double moment(double area, double slip) { return MU * area * slip; } /** * Calculate (in SI units) the average slip across a fault area with the * supplied moment, assuming a shear modulus of {@link #MU}. If moment * <em>rate</em> is supplied, slip <em>rate</em> is returned. * * @param area in m² * @param moment <em>M</em>₀ in N·m (or moment rate in N·m·t⁻¹) * @return slip in m (or slip rate in m·t⁻¹) */ public static double slip(double area, double moment) { return moment / (area * MU); } }