Source code for openquake.hazardlib.gsim.macedo_2019

# -*- coding: utf-8 -*-
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright (C) 2025 GEM Foundation
#
# OpenQuake is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# OpenQuake is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with OpenQuake. If not, see <http://www.gnu.org/licenses/>.
"""
Module exports: :class:`MacedoEtAl2019SInter`,
                :class:`MacedoEtAl2019SSlab`
"""

import numpy as np
from openquake.hazardlib import const
from openquake.hazardlib.imt import IA, PGA, SA
from openquake.hazardlib.gsim.base import GMPE, registry
from openquake.hazardlib.contexts import get_mean_stds


# The Macedo et al. (2019) GMM is period-independent, so all constants
# can be set as a standard dictionary
CONSTANTS = {
    "sinter": {
        # Global from Table 1
        "Global": {
            "c1": 0.85, "c2": -0.36, "c3": 0.53, "c4": 1.54,
            "c5": 0.17, "phi": 0.30, "tau_region": 0.04, "tau": 0.18,
        },
        # Regional coefficients for Interface events from Table 2
        "Japan": {
            "c1": 0.98, "c2": -0.38, "c3": 0.53, "c4": 1.54,
            "c5": 0.17, "phi": 0.3, "tau_region": 0.0, "tau": 0.16,
        },
        "Taiwan": {
            "c1": 0.75, "c2": -0.35, "c3": 0.53, "c4": 1.54,
            "c5": 0.17, "phi": 0.27, "tau_region": 0.0, "tau": 0.15,
        },
        "South America": {
            "c1": 0.95, "c2": -0.36, "c3": 0.53, "c4": 1.54,
            "c5": 0.17, "phi": 0.32, "tau_region": 0.0, "tau": 0.19,
        },
        "New Zealand": {
            "c1": 0.82, "c2": -0.36, "c3": 0.53, "c4": 1.54,
            "c5": 0.17, "phi": 0.28, "tau_region": 0.0, "tau": 0.17,
        },
    },
    "sslab": {
        # Global from Table 1
        "Global": {
            "c1": -0.74, "c2": -0.24, "c3": 0.66, "c4": 1.58,
            "c5": 0.14, "phi": 0.28, "tau_region": 0.03, "tau": 0.16
        },
        # Regional coefficients for Interface events from Table 3
        "Japan": {
            "c1": -0.22, "c2": -0.32, "c3": 0.66, "c4": 1.58,
            "c5": 0.14, "phi": 0.26, "tau_region": 0.0, "tau": 0.15,
        },
        "Taiwan": {
            "c1": -1.02, "c2": -0.20, "c3": 0.66, "c4": 1.58,
            "c5": 0.14, "phi": 0.29, "tau_region": 0.0, "tau": 0.17,
        },
        "South America": {
            "c1": -0.75, "c2": -0.24, "c3": 0.66, "c4": 1.58,
            "c5": 0.14, "phi": 0.30, "tau_region": 0.0, "tau": 0.14,
        },
        "New Zealand": {
            "c1": -0.84, "c2": -0.22, "c3": 0.66, "c4": 1.58,
            "c5": 0.14, "phi": 0.3, "tau_region": 0.0, "tau": 0.13,
        },
    }
}


[docs]def get_mean_conditional_arias_intensity( C: dict, ctx: np.recarray, mean_gms: np.recarray ) -> np.ndarray: """ Returns the Arias Intensity (Equation 2) """ return (C["c1"] + C["c2"] * np.log(ctx.vs30) + C["c3"] * ctx.mag + C["c4"] * mean_gms["PGA"] + C["c5"] * mean_gms["SA(1.0)"])
[docs]def get_stddev_component( C: dict, sig_ia_cond: float, sig_pga: float, sig_sa1: float, rho: float ) -> float: """ Returns the standard deviation using Equation 6. Assume this can apply to all three components of stddev """ return np.sqrt( sig_ia_cond ** 2.0 + (sig_pga ** 2.0) * (C["c4"] ** 2.0) + (sig_sa1 ** 2.0) * (C["c5"] ** 2.0) + (2.0 * (rho * sig_pga * sig_sa1) * C["c4"] * C["c5"]))
[docs]def get_standard_deviations( C: dict, kind: str, rho_pga_sa1: float, sigma_gms: np.recarray, tau_gms: np.recarray, phi_gms: np.recarray): """ Returns sigma, tau and phi arrays for Arias Intensity """ sigma_ia_cond = 0.36 if kind == "sinter" else 0.33 # Gets the total standard deviation sigma = get_stddev_component(C, sigma_ia_cond, sigma_gms["PGA"], sigma_gms["SA(1.0)"], rho_pga_sa1) if np.any(tau_gms["PGA"] >= 0.0) or np.any(tau_gms["SA(1.0)"] > 0.0): # If provided by the conditioning ground motion, get the # between-event standard deviation tau = get_stddev_component( C, np.sqrt(C["tau"]**2 + C["tau_region"]**2), tau_gms["PGA"], tau_gms["SA(1.0)"], rho_pga_sa1) else: tau = 0.0 if np.any(phi_gms["PGA"] >= 0.0) or np.any(phi_gms["SA(1.0)"] > 0.0): # If provided by the conditioning ground motion, get the # within-event standard deviation phi = get_stddev_component( C, C["phi"], phi_gms["PGA"], phi_gms["SA(1.0)"], rho_pga_sa1) else: phi = 0.0 return sigma, tau, phi
[docs]class MacedoEtAl2019SInter(GMPE): """Implementation of a conditional GMPE of Macedo, Abrahamson & Bray (2019) for Arias Intensity, applied to subduction interface earthquakes. This requires characterisation of the PGA and SA(1.0), in addition to magnitude and vs30, for defining Arias intensity, and propagates uncertainty accordingly. The model includes specific regionalisations for "Global" application (default), "Japan", "Taiwan", "New Zealand" and "South America", as well as a user customisable coefficient of correlation between PGA and SA(1.0). Macedo J, Abrahamson N, Bray JD (2019) "Arias Intensity Conditional Scaling Ground-Motion Models for Subduction Zones", Bulletin of the Seismological Society of America, 109(4): 1343 - 1357 """ DEFINED_FOR_TECTONIC_REGION_TYPE = const.TRT.SUBDUCTION_INTERFACE DEFINED_FOR_INTENSITY_MEASURE_TYPES = {IA, PGA, SA} # It is unclear to me if the CGMM is for a specific component of Arias # Intensity; however it's fit using NGA Subduction data, which assumes # PGA and SA are in terms of RotD50 DEFINED_FOR_INTENSITY_MEASURE_COMPONENT = const.IMC.RotD50 DEFINED_FOR_STANDARD_DEVIATION_TYPES = { const.StdDev.TOTAL, const.StdDev.INTER_EVENT, const.StdDev.INTRA_EVENT} REQUIRES_SITES_PARAMETERS = {"vs30", "backarc"} REQUIRES_RUPTURE_PARAMETERS = {"mag", } REQUIRES_DISTANCES = {'rrup'} # Subduction interface kind = "sinter" # Conditional upon PGA and Sa (1.0 s) REQUIRES_IMTS = {PGA(), SA(1.0)} # GMPE not verified against an independent implementation non_verified = True def __init__(self, region: str="Global", rho_pga_sa1: float=0.52, **gmpe_dict): """ Args: region: Region of application. Must be either "Global" (default) or one of "Japan", "Taiwan", "South America", "New Zealand" rho_pga_sa1: Coefficient of correlation in total standard deviation between PGA and Sa (1.0 s). In the original paper this is taken as 0.52, based on the cross-correlation model of Baker & Jayaram (2008). The coefficient could be configured by the user if they wish to adopt an alternative cross-correlation model gmpe_dict: dictionary specifying the underlying GMPE """ # check that the region is one of those supported assert region in ("Global", "Japan", "Taiwan", "South America", "New Zealand"),\ "Region %s not recognised for Macedo et al (2019) GMPE" % region self.region = region self.rho_pga_sa1 = rho_pga_sa1 # instantiate the underlying gmpe [(gmpe_name, kw)] = gmpe_dict.pop('gmpe').items() self.gmpe = registry[gmpe_name](**kw)
[docs] def compute(self, ctx: np.recarray, imts: list, mean: np.ndarray, sig: np.ndarray, tau: np.ndarray, phi: np.ndarray): """ Calculates the mean Arias Intensity and the standard deviations """ # NB: there is a single IMT, Arias Intensity, i.e. imts == [IA] me, si, ta, ph = get_mean_stds( self.gmpe, ctx, self.REQUIRES_IMTS, return_dicts=True) C = CONSTANTS[self.kind][self.region] mean[0] = get_mean_conditional_arias_intensity(C, ctx, me) sigma_m, tau_m, phi_m = get_standard_deviations( C, self.kind, self.rho_pga_sa1, si, ta, ph) sig[0] += sigma_m tau[0] += tau_m phi[0] += phi_m
[docs]class MacedoEtAl2019SSlab(MacedoEtAl2019SInter): """ Macedo et al. (2019) GMPE for application to subduction in-slab earthquakes """ DEFINED_FOR_TECTONIC_REGION_TYPE = const.TRT.SUBDUCTION_INTRASLAB kind = "sslab"