# -*- coding: utf-8 -*-
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright (C) 2014-2023 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:`CampbellBozorgnia2003`
                class:`CampbellBozorgnia2003Vertical`.
"""
import numpy as np
from openquake.hazardlib.gsim.base import GMPE, CoeffsTable
from openquake.hazardlib import const
from openquake.hazardlib.imt import PGA, SA
from openquake.hazardlib.gsim.campbell_bozorgnia_2003 import (
    _compute_magnitude_scaling, _compute_faulting_mechanism 
)
def _get_mean(C, mag, rake, dip, rrup, rjb, vs30):
    """
    Return mean value (eq. 1, page 319).
    """
    f1 = _compute_magnitude_scaling(C, mag)
    f2 = _compute_distance_scaling(C, mag, rrup, vs30)
    f3 = _compute_faulting_mechanism(C, rake, dip)
    f4 = _compute_far_source_soil_effect(C, vs30)
    f5 = _compute_hanging_wall_effect(C, rjb, rrup, dip, mag, rake, vs30)
    return C['c1'] + f1 + C['c4'] * np.log(np.sqrt(f2)) + f3 + f4 + f5
def _compute_distance_scaling(C, mag, rrup, vs30):
    """
    Compute distance scaling term (eq.3, page 319).
    """
    svfs , ssr, sfr = _get_site_type_dummy_variables(vs30)
    g = C['c5'] + C['c6'] * (svfs + ssr) + C['c7'] * sfr
    return rrup ** 2 + (np.exp(
        C['c8'] * mag + C['c9'] * (8.5 - mag) ** 2) * g) ** 2
def _get_site_type_dummy_variables(vs30):
        """
        Get site type dummy variables, four site types are considered
        based on the shear wave velocity intervals in the uppermost 30 m, Vs30:
        firm soil: 298 < Vs30 <= 368 m/s
        very firm soil: 368 < Vs30 <= 421 m/s
        soft rock: 421 < Vs30 <= 830 m/s
        firm rock: Vs30 > 830 m/s
        """
        svfs = np.zeros(len(vs30))
        ssr = np.zeros(len(vs30))
        sfr = np.zeros(len(vs30))
        # very firm soil
        idx = (vs30 >= 368) & (vs30 <= 421)
        svfs[idx] = 1.0
        # soft rock
        idx = (vs30 > 421) & (vs30 <= 830)
        ssr[idx] = 1.0
        # firm rock
        idx = (vs30 > 830)
        sfr[idx] = 1.0
        return svfs, ssr ,sfr
def _compute_far_source_soil_effect(C, vs30):
    """
    Compute far-source effect of local site conditions (see eq. 6,
    page 319).
    """
    svfs , ssr, sfr = _get_site_type_dummy_variables(vs30)
    return C['c12']*svfs + C['c13']*ssr + C['c14']*sfr
def _compute_hanging_wall_effect(C, rjb, rrup, dip, mag, rake, vs30):
    """
    Compute hanging-wall effect (see eq. 7, 8, 9 and 10 page 319).
    Considers correct version of equation 8 as given in the erratum and not
    in the original paper.
    """
    # flag for reverse faulting
    frv = (dip > 45) & (22.5 <= rake) & (rake <= 157.5)
    # flag for thrust faulting
    fth = (dip <= 45) & (22.5 <= rake) & (rake <= 157.5)
    
    svfs , ssr, sfr = _get_site_type_dummy_variables(vs30)
    # eq. 8
    hw = np.zeros_like(rjb)
    idx1 = rjb < 5
    svfs = ((svfs*((5 - rjb) / 5))*idx1 + 0.0)*(dip <= 70)
    ssr  = ((ssr*((5 - rjb) / 5))*idx1 + 0.0)*(dip <= 70)
    sfr  = ((sfr*((5 - rjb) / 5))*idx1 + 0.0)*(dip <= 70)
    hw = svfs+ssr+sfr
    # eq. 9
    f_m = np.where(mag>6.5, 1, np.where(mag<5.5, 0, mag-5.5))
    # eq. 10
    f_rrup = C['c15'] + np.zeros_like(rrup)
    idx = rrup < 8
    f_rrup[idx] *= rrup[idx] / 8
    # eq. 7
    f_hw = (hw * f_m * f_rrup * (frv + fth))
    return f_hw
[docs]class CampbellBozorgnia2003(GMPE):
    """
    Implements GMPE developed by Kenneth W. Campbell and Yousef Bozorgnia and
    published as "Updated Near-Source Ground-Motion (Attenuation) Relations for
    the Horizontal and Vertical Components of Peak Ground Acceleration and
    Acceleration Response Spectra", Bulletin of the Seismological Society of
    America, Vol. 93, No. 1, pp. 314-331, 2003.
    """
    #: Supported tectonic region type is 'active shallow crust' (see Abstract)
    DEFINED_FOR_TECTONIC_REGION_TYPE = const.TRT.ACTIVE_SHALLOW_CRUST
    #: Supported intensity measure types are PGA and SA (see Abstract)
    DEFINED_FOR_INTENSITY_MEASURE_TYPES = {PGA, SA}
    #: Supported intensity measure component is the geometric mean of two
    #: horizontal components (see paragraph 'Strong-Motion Database', page 316)
    DEFINED_FOR_INTENSITY_MEASURE_COMPONENT = const.IMC.GEOMETRIC_MEAN
    #: Supported standard deviation type is Total (see equations 11, 12 pp. 319
    #: 320)
    DEFINED_FOR_STANDARD_DEVIATION_TYPES = {const.StdDev.TOTAL}
    #: Required site parameter is only Vs30
    REQUIRES_SITES_PARAMETERS = {'vs30'}
    #: Required rupture parameters are magnitude, rake and dip (eq. 1 and
    #: following, page 319).
    REQUIRES_RUPTURE_PARAMETERS = {'mag', 'rake', 'dip'}
    #: Required distance measure are RRup and Rjb (eq. 1 and following,
    #: page 319).
    REQUIRES_DISTANCES = {'rrup', 'rjb'}
[docs]    def compute(self, ctx: np.recarray, imts, mean, sig, tau, phi):
        """
        See :meth:`superclass method
        <.base.GroundShakingIntensityModel.compute>`
        for spec of input and result values.
        """
        for m, imt in enumerate(imts):
            C = self.COEFFS[imt]
            mean[m] = _get_mean(
                C, ctx.mag, ctx.rake, ctx.dip, ctx.rrup, ctx.rjb, ctx.vs30)
            sig[m] = C['c16'] - np.where(ctx.mag < 7.4, 0.07 * ctx.mag, 0.518) 
    #: Coefficient table (table 4, page 321. Coefficients for horizontal
    #: component SA and for corrected PGA)
    COEFFS = CoeffsTable(sa_damping=5, table="""\
    IMT	     c1	    c2	     c3	     c4	    c5	     c6	     c7	    c8	     c9	     c10	c11	     c12	 c13	 c14	c15	    c16
    PGA	    -4.033	0.812	 0.036	-1.061	0.041	-0.005	-0.018	0.766	 0.034	 0.343	0.351	-0.123	-0.138	-0.289	0.370	0.920
    0.05	-3.740	0.812	 0.036	-1.121	0.058	-0.004	-0.028	0.724	 0.032	 0.302	0.362	-0.140	-0.158	-0.205	0.370	0.940
    0.08	-3.076	0.812	 0.050	-1.252	0.121	-0.005	-0.051	0.648	 0.040	 0.243	0.333	-0.150	-0.196	-0.208	0.370	0.952
    0.10	-2.661	0.812	 0.060	-1.308	0.166	-0.009	-0.068	0.621	 0.046	 0.224	0.313	-0.146	-0.253	-0.258	0.370	0.958
    0.15	-2.270	0.812	 0.041	-1.324	0.212	-0.033	-0.081	0.613	 0.031	 0.318	0.344	-0.176	-0.267	-0.284	0.370	0.974
    0.20	-2.771	0.812	 0.030	-1.153	0.098	-0.014	-0.038	0.704	 0.026	 0.296	0.342	-0.148	-0.183	-0.359	0.370	0.981
    0.30	-2.999	0.812	 0.007	-1.080	0.059	-0.007	-0.022	0.752	 0.007	 0.359	0.385	-0.162	-0.157	-0.585	0.370	0.984
    0.40	-3.511	0.812	-0.015	-0.964	0.024	-0.002	-0.005	0.842	-0.016	 0.379	0.438	-0.078	-0.129	-0.557	0.370	0.987
    0.50	-3.556	0.812	-0.035	-0.964	0.023	-0.002	-0.004	0.842	-0.036	 0.406	0.479	-0.122	-0.130	-0.701	0.370	0.990
    0.75	-3.709	0.812	-0.071	-0.964	0.021	-0.002	-0.002	0.842	-0.074	 0.347	0.419	-0.108	-0.124	-0.796	0.331	1.021
    1.00	-3.867	0.812	-0.101	-0.964	0.019	 0.000	 0.000	0.842	-0.105	 0.329	0.338	-0.073	-0.072	-0.858	0.281	1.021
    1.50	-4.093	0.812	-0.150	-0.964	0.019	 0.000	 0.000	0.842	-0.155	 0.217	0.188	-0.079	-0.056	-0.954	0.210	1.021
    2.00	-4.311	0.812	-0.180	-0.964	0.019	 0.000	 0.000	0.842	-0.187	 0.060	0.064	-0.124	-0.116	-0.916	0.160	1.021
    3.00	-4.817	0.812	-0.193	-0.964	0.019	 0.000	 0.000	0.842	-0.200	-0.079	0.021	-0.154	-0.117	-0.873	0.089	1.021
    4.00	-5.211	0.812	-0.202	-0.964	0.019	 0.000	 0.000	0.842	-0.209	-0.061	0.057	-0.054	-0.261	-0.889	0.039	1.021
    """) 
[docs]class CampbellBozorgnia2003Vertical(CampbellBozorgnia2003):
    #: Supported intensity measure component is vertical
    DEFINED_FOR_INTENSITY_MEASURE_COMPONENT = const.IMC.VERTICAL
    #: Coefficient table (table 4, page 321. Coefficients for vertical
    #: component SA and for corrected PGA)
    COEFFS = CoeffsTable(sa_damping=5, table="""\
    IMT	     c1	    c2	     c3	     c4	    c5	     c6	     c7	    c8	     c9	     c10	c11	     c12	 c13	 c14	c15	    c16
    PGA	    -3.108	0.756	 0.000	-1.287	0.142	0.046	-0.040	0.587	 0.000	0.253	0.173	-0.135	-0.138	-0.256	0.630	0.975
    0.05	-1.918	0.756	 0.000	-1.517	0.309	0.069	-0.023	0.498	 0.000	0.058	0.100	-0.195	-0.274	-0.219	0.630	1.031
    0.08	-1.504	0.756	 0.000	-1.551	0.343	0.083	 0.000	0.487	 0.000	0.135	0.182	-0.224	-0.303	-0.263	0.630	1.031
    0.10	-1.672	0.756	 0.000	-1.473	0.282	0.062	 0.001	0.513	 0.000	0.168	0.210	-0.198	-0.275	-0.252	0.630	1.031
    0.15	-2.323	0.756	 0.000	-1.280	0.171	0.045	 0.008	0.591	 0.000	0.223	0.238	-0.170	-0.175	-0.270	0.630	1.031
    0.20	-2.998	0.756	 0.000	-1.131	0.089	0.028	 0.004	0.668	 0.000	0.234	0.256	-0.098	-0.041	-0.311	0.571	1.031
    0.30	-3.721	0.756	 0.007	-1.028	0.050	0.010	 0.004	0.736	 0.007	0.249	0.328	-0.026	 0.082	-0.265	0.488	1.031
    0.40	-4.536	0.756	-0.015	-0.812	0.012	0.000	 0.000	0.931	-0.018	0.299	0.317	-0.017	 0.022	-0.257	0.428	1.031
    0.50	-4.651	0.756	-0.035	-0.812	0.012	0.000	 0.000	0.931	-0.043	0.243	0.354	-0.020	 0.092	-0.293	0.383	1.031
    0.75	-4.903	0.756	-0.071	-0.812	0.012	0.000	 0.000	0.931	-0.087	0.295	0.418	 0.078	 0.091	-0.349	0.299	1.031
    1.00	-4.950	0.756	-0.101	-0.812	0.012	0.000	 0.000	0.931	-0.124	0.266	0.315	 0.043	 0.101	-0.481	0.240	1.031
    1.50	-5.073	0.756	-0.150	-0.812	0.012	0.000	 0.000	0.931	-0.184	0.171	0.211	-0.038	-0.018	-0.518	0.240	1.031
    2.00	-5.292	0.756	-0.180	-0.812	0.012	0.000	 0.000	0.931	-0.222	0.114	0.115	 0.033	-0.022	-0.503	0.240	1.031
    3.00	-5.748	0.756	-0.193	-0.812	0.012	0.000	 0.000	0.931	-0.238	0.179	0.159	-0.010	-0.047	-0.539	0.240	1.031
    4.00	-6.042	0.756	-0.202	-0.812	0.012	0.000	 0.000	0.931	-0.248	0.237	0.134	-0.059	-0.267	-0.606	0.240	1.031
    """)