Source code for openquake.hazardlib.gsim.nz22.atkinson_2022
# -*- coding: utf-8 -*-# vim: tabstop=4 shiftwidth=4 softtabstop=4## Copyright (C) 2015-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:`Atkinson2022Crust` :class:`Atkinson2022SSlab` :class:`Atkinson2022SInter`"""frompathlibimportPathimportnumpyasnpfromscipy.interpolateimportinterp1dfromopenquake.hazardlibimportconstfromopenquake.hazardlib.gsim.baseimportGMPE,CoeffsTablefromopenquake.hazardlib.gsim.nz22.constimport(periods_AG20,rho_Ws,rho_Bs,periods,theta7s,theta8s,)fromopenquake.hazardlib.imtimportPGA,SAAtk22_COEFFS=Path(Path(__file__).parent,"Atkinson22_coeffs_mod_v8b_sanjay_v2.csv")def_fmag(suffix,C,mag):""" ctx.magnitude factor """ifsuffix=="slab":# res = C['c0_' + suffix] + C['c1_' + suffix] * (mag - 6.0) + C['c2_' + suffix] * (mag - 6.0) ** 2# Modified as in RevisionsToBackbonev8 from Gail received on 21.06.2022.res=(C["c0_"+suffix]+C["c1_"+suffix]*mag+C["c2_"+suffix]*mag**2)else:res=C["c0_crust"]+C["c1_crust"]*mag+C["c2_crust"]*mag**2returnresdef_fz_ha18(C,ctx):""" Implements eq. 2,3,4,5 from page 5 """# pseudo-depth# h = 10 ** (-0.1 + 0.2 * ctx.mag) The h term is modified after# receiving the modifications from Gail on Slack on 12.06.2022. h# = 10 ** (0.3 + 0.11 * ctx.mag) Modified as in# RevisionsToBackbonev8 from Gail received on 21.06.2022. However,# there is a typo.h=10**(-0.405+0.235*ctx.mag)R=np.sqrt(ctx.rrup**2+h**2)Rref=np.sqrt(1+h**2)# The transition_distanceRt=50# Geometrical spreading ratesb1=-1.3b2=-0.5# Geometrical attenuationz=R**b1ratio=R/Rtz[R>Rt]=Rt**b1*(ratio[R>Rt])**b2returnnp.log(z)+(C["b3"]+C["b4"]*ctx.mag)*np.log(R/Rref)def_fgamma(suffix,C,ctx):ifsuffix=="crust":g1=min(0.008,0.005+0.0016*np.log(C["f"]))elifsuffix=="inter":g1=min(0.006,0.0045+0.0014*np.log(C["f"]))else:g1=min(0.005,0.004+0.0012*np.log(C["f"]))# a2 = max(0.002 + 0.0025 * np.log(max(C['f'], 35)), 0.0015)# a3 = 0.009 - 0.001 * np.log(max(C['f'], 35))# g2 = min(min(0.0065, a2), a3)gamma=np.zeros(ctx.rrup.shape)# gamma = -g1 * ctx.rrup + g2*(270.0 - np.clip(ctx.rrup, 270,# None)) Gail mentioned in personal communication (email# 13.06.2022) that now the modified F_gamma (see eq. 20-22 in# modifications posted on Salck 12.06.2022) does not include# gamma_2 term.gamma=-g1*ctx.rrupreturngammadef_epistemic_adjustment_lower(C,ctx):# These are revised adjustments after Gail's post on slack 11th# May 2022 and in her revised report. The lower branch adjustment# remains the same. a = np.fmax(np.clip(0.5 - 0.1 *# np.log(ctx.rrup), 0.2, None), - 0.25 + 0.1 * np.log(ctx.rrup))# The following variable is after Gail's modifications received on# Slack 12.06.2022 The additional epistemic uncertainty for M>7# events was added in Gail's V8 modifications shared on 27.06.2022a=np.fmax(np.clip(0.6-0.13*np.log(ctx.rrup),0.3,None),-0.25+0.12*np.log(ctx.rrup),)returnnp.clip(a,-np.inf,0.5)+0.15*np.clip(ctx.mag-7.0,0,np.inf)def_epistemic_adjustment_upper(C,ctx):# These are revised adjustments after Gail's post on slack 11th# May 2022 and in her revised report. Only the upper brach is# modified. a = np.fmax(np.clip(1.0 - 0.27 * np.log(ctx.rrup),# 0.2, None), - 0.25 + 0.1 * np.log(ctx.rrup)) The following# variable is after Modification from Gail recieved on Slack# 12.06.2022 The additional epistemic uncertainty for M>7 events# was added in Gail's V8 modifications shared on 27.06.2022a=np.fmax(np.clip(1.0-0.3*np.log(ctx.rrup),0.3,None),-0.25+0.12*np.log(ctx.rrup),)returnnp.clip(a,-np.inf,0.8)+0.15*np.clip(ctx.mag-7.0,0,np.inf)
[docs]deffs_SS14(C,pga_rock,ctx):# The site-term is implemnted from Seyhan and Stewart (2014; EQS).Vs_ref=760.0flin=ctx.vs30/Vs_refflin[ctx.vs30>C["Vc"]]=C["Vc"]/Vs_refflin_func=C["c"]*np.log(flin)v_s=np.copy(ctx.vs30)v_s[ctx.vs30>760.0]=760.0f_1=0.0f_3=0.1*981.0# In Gail's model the GMM is in cm/s^2.# Nonlinear controlling parameter (equation 8)f_2=C["f4"]*(np.exp(C["f5"]*(v_s-360.0))-np.exp(C["f5"]*400.0))fnl=f_1+f_2*np.log((pga_rock+f_3)/f_3)returnflin_func+fnl
[docs]defget_stddevs(suffix,C):r""" Standard deviations given in COEFFS with suffix between event standard deviations as Be\_ within event stdvs as We\_ total as sigma\_ """intra_e_sigma=np.sqrt(C["We_"+suffix]**2+C["phiS2S"]**2)return[C["sigma_"+suffix],C["Be_"+suffix],intra_e_sigma]
[docs]defget_nonlinear_stddevs(suffix,C,C_PGA,imt,pga_rock,vs30):""" Get the nonlinear tau and phi terms for Gail's model. For this implementation, I using the between-event and within-event correlation from AG20. Note that the Gail's nonlinear soil response term is identical to Seyhan and Stewart (2014) model. """period=imt.periodpgar=pga_rock/981.0# Linear Tautau_lin=C["Be_"+suffix]*np.ones(vs30.shape)tau_lin_pga=C_PGA["Be_"+suffix]*np.ones(vs30.shape)# Linear phiintra_e_sigma=np.sqrt(C["We_"+suffix]**2+C["phiS2S"]**2)intra_e_sigma_pga=np.sqrt(C_PGA["We_"+suffix]**2+C_PGA["phiS2S"]**2)phi_lin=intra_e_sigma*np.ones(vs30.shape)phi_lin_pga=intra_e_sigma_pga*np.ones(vs30.shape)# Assume that the site response variability is constant with period.phi_amp=0.3phi_B=np.sqrt(phi_lin**2-phi_amp**2)phi_B_pga=np.sqrt(phi_lin_pga**2-phi_amp**2)rho_W_itp=interp1d(np.log(periods_AG20),rho_Ws)rho_B_itp=interp1d(np.log(periods_AG20),rho_Bs)ifperiod<0.01:rhoW=1.0rhoB=1.0else:rhoW=rho_W_itp(np.log(period))rhoB=rho_B_itp(np.log(period))f2=C["f4"]*(np.exp(C["f5"]*(np.minimum(vs30,760.0)-360.0))-np.exp(C["f5"]*(760.0-360.0)))f3=0.1partial_f_pga=f2*pgar/(pgar+f3)partial_f_pga=partial_f_pga*np.ones(vs30.shape)# nonlinear variance componentsphi2_NL=(phi_lin**2+partial_f_pga**2*phi_B_pga**2+2*partial_f_pga*phi_B_pga*phi_B*rhoW)tau2_NL=(tau_lin**2+partial_f_pga**2*tau_lin_pga**2+2*partial_f_pga*tau_lin_pga*tau_lin*rhoB)# return [partial_f_pga, np.sqrt(tau2_NL), np.sqrt(phi2_NL)]return[np.sqrt(tau2_NL+phi2_NL),np.sqrt(tau2_NL),np.sqrt(phi2_NL)]
[docs]defget_backarc_term(trt,imt,ctx):""" The backarc correction factors to be applied with the ground motion prediction. In the NZ context, it is applied to only subduction intraslab events. It is essentially the correction factor taken from BC Hydro 2016. Abrahamson et al. (2016) Earthquake Spectra. The correction is applied only for backarc sites as function of distance. """period=imt.periodw_epi_factor=1.008theta7_itp=interp1d(np.log(periods[1:]),theta7s[1:])theta8_itp=interp1d(np.log(periods[1:]),theta8s[1:])# Note that there is no correction for PGV. Hence, I make theta7 and theta8 as 0 for periods < 0.ifperiod<0:theta7=0.0theta8=0.0elifperiod>=0andperiod<0.02:theta7=1.0988theta8=-1.42else:theta7=theta7_itp(np.log(period))theta8=theta8_itp(np.log(period))dists=ctx.rrupiftrt==const.TRT.SUBDUCTION_INTRASLAB:min_dist=85.0backarc=np.bool_(ctx.backarc)f_faba=np.zeros_like(dists)fixed_dists=dists[backarc]fixed_dists[fixed_dists<min_dist]=min_distf_faba[backarc]=theta7+theta8*np.log(fixed_dists/40.0)returnf_faba*w_epi_factorelse:f_faba=np.zeros_like(dists)returnf_faba
[docs]classAtkinson2022Crust(GMPE):""" Implements Atkinson (2022) backbone model for New Zealand. For more info please refere to Gail Atkinson's NSHM report and linked revisions. """DEFINED_FOR_TECTONIC_REGION_TYPE=const.TRT.ACTIVE_SHALLOW_CRUST#: Supported intensity measure types are spectral acceleration,#: peak ground accelerationDEFINED_FOR_INTENSITY_MEASURE_TYPES={PGA,SA}#: Supported intensity measure component is the RotD50DEFINED_FOR_INTENSITY_MEASURE_COMPONENT=const.IMC.RotD50DEFINED_FOR_STANDARD_DEVIATION_TYPES={const.StdDev.TOTAL,const.StdDev.INTER_EVENT,const.StdDev.INTRA_EVENT,}REQUIRES_DISTANCES={"rrup"}REQUIRES_RUPTURE_PARAMETERS={"mag"}REQUIRES_SITES_PARAMETERS={"vs30"}# define the epistemic uncertainities : Central/Lower/UpperREQUIRES_ATTRIBUTES={"epistemic"}# define constant parameterssuffix="crust"def__init__(self,epistemic="Central",modified_sigma=False):""" Aditional parameter for epistemic central, lower and upper bounds. """self.epistemic=epistemicself.modified_sigma=modified_sigma
[docs]defcompute(self,ctx:np.recarray,imts,mean,sig,tau,phi):trt=self.DEFINED_FOR_TECTONIC_REGION_TYPEC_PGA=self.COEFFS[PGA()]pga_rock=_get_pga_on_rock(self.suffix,C_PGA,ctx)*np.exp(get_backarc_term(trt,PGA(),ctx))# Here the backarc term is applied as multiplication because the# pga_rock is in linear space not in log spaceform,imtinenumerate(imts):C=self.COEFFS[imt]# compute meanmean[m]=(_fmag(self.suffix,C,ctx.mag)+_fz_ha18(C,ctx)+_fgamma(self.suffix,C,ctx)+fs_SS14(C,pga_rock,ctx)+get_backarc_term(trt,imt,ctx))mean[m]=mean[m]-np.log(981.0)# Convert the cm/s^2 to g.# In her email and slack post Gail mentioned that her# upper and lower branches are as 1.28 times of the delta.# So as to represent 10th and 90th percentile.# Consequently, the weights have also changed to 0.3, 0.4,# 0.3. The scale factor of 0.9 is applied based upon the# discussion that it accounts for the reduction in# epistemic uncertainty when no perfect correlation is# assumed between rupture scenarios. See the note of Peter# and Brendon on slack.epistemic_scale_factor=0.893ifself.epistemic.lower()=="lower":mean[m]=(mean[m]-_epistemic_adjustment_lower(C,ctx)*1.28155*epistemic_scale_factor)elifself.epistemic.lower()=="upper":mean[m]=(mean[m]+_epistemic_adjustment_upper(C,ctx)*1.28155*epistemic_scale_factor)else:mean[m]=mean[m]# Aleatory Uncertainty terms.ifself.modified_sigma:sig[m],tau[m],phi[m]=get_nonlinear_stddevs(self.suffix,C,C_PGA,imt,pga_rock,ctx.vs30)else:sig[m],tau[m],phi[m]=get_stddevs(self.suffix,C)
# periods given by 1 / 10 ** COEFFS['f']withAtk22_COEFFS.open()ascoefs_file:COEFFS=CoeffsTable(sa_damping=5,table=coefs_file.read())
[docs]classAtkinson2022SInter(Atkinson2022Crust):""" Atkinson 2022 for Subduction Interface in NZ. """DEFINED_FOR_TECTONIC_REGION_TYPE=const.TRT.SUBDUCTION_INTERFACE# constant table suffixsuffix="inter"
# stress = 100
[docs]classAtkinson2022SSlab(Atkinson2022Crust):""" Atkinson (2022) for Subduction IntraSlab in NZ. """DEFINED_FOR_TECTONIC_REGION_TYPE=const.TRT.SUBDUCTION_INTRASLAB# constant table suffixsuffix="slab"REQUIRES_SITES_PARAMETERS={"vs30","backarc"}