def site_term(self, ctx, dists, imt): """ Site term as used to calculate site coefficients for NBCC2015: For Vs30 > 760 m/s use log-log interpolation of the 760-to-2000 factor of AA13. For Vs30 < 760 m/s use the site term of Boore and Atkinson 2008. Original site term is relative to Vs30 = 760m/s so needs to be made relative to Vs30 = 450 m/s by dividing by the site term at Vs30 = 450. Assume PGA_760 = 0.1g for Vs30 > 450 m/s. Also need to correct PGA at site class C to 760 m/s. Cap PGA_450 at 0.1 - 0.5g. """ imls_pga = _return_tables(self, ctx.mag, PGA(), "IMLs") PGA450 = _get_mean(self.kind, self.distance_type, imls_pga, ctx, dists) imls_SA02 = _return_tables(self, ctx.mag, SA(0.2), "IMLs") SA02 = _get_mean(self.kind, self.distance_type, imls_SA02, ctx, dists) PGA450[SA02 / PGA450 < 2.0] = PGA450[SA02 / PGA450 < 2.0] * 0.8 pgas = np.array([0.1, 0.2, 0.3, 0.4, 0.5]) pga_cors = np.array([0.083, 0.165, 0.248, 0.331, 0.414]) PGA760 = np.interp(PGA450, pgas, pga_cors) PGA760_ref = np.copy(PGA760) PGA760_ref[ctx.vs30 > 450.] = 0.1 vs30ref = np.zeros_like(ctx.vs30) vs30ref += 450.0 C = self.COEFFS_2000_to_BC[imt] site_term = (AB06_BA08(C, ctx.vs30, imt, PGA760_ref) / AB06_BA08(C, vs30ref, imt, PGA760_ref)) return np.log(site_term)
def test_retreival_tables_outside_period_range(self): """ Tests that an error is raised when inputting a period value outside the supported range """ gsim = GMPETable(gmpe_table=self.TABLE_FILE) with self.assertRaises(ValueError) as ve: _return_tables(gsim, 6.0, imt_module.SA(2.5), "IMLs") self.assertEqual( str(ve.exception), "Spectral period 2.500 outside of valid range (0.100 to 2.000)")
def test_retreival_tables_outside_mag_range(self): """ Tests that an error is raised when inputting a magnitude value outside the supported range """ gsim = GMPETable(gmpe_table=self.TABLE_FILE) with self.assertRaises(ValueError) as ve: _return_tables(gsim, 4.5, imt_module.PGA(), "IMLs") self.assertEqual( str(ve.exception), "Magnitude 4.50 outside of supported range (5.00 to 7.00)")
def test_retreival_tables_good_interp(self): """ Tests the retreival of the IML tables for 'good' conditions with magnitude interpolations """ gsim = GMPETable(gmpe_table=self.TABLE_FILE) expected_table_pgv = np.array( [midpoint(20., 40.), midpoint(10., 20.), midpoint(5., 10.)]) np.testing.assert_array_almost_equal( _return_tables(gsim, 6.5, imt_module.PGV(), "IMLs"), expected_table_pgv, 5) expected_table_sa1 = np.array( [midpoint(2., 4.), midpoint(1., 2.), midpoint(0.5, 1.)]) np.testing.assert_array_almost_equal( _return_tables(gsim, 6.5, imt_module.SA(1.0), "IMLs"), expected_table_sa1)
def get_hard_rock_mean(self, ctx, imt): """ Returns the mean and standard deviations for the reference very hard rock condition (Vs30 = 3000 m/s) """ # Return Distance Tables imls = _return_tables(self, ctx.mag, imt, "IMLs") # Get distance vector for the given magnitude idx = np.searchsorted(self.m_w, ctx.mag) dists = self.distances[:, 0, idx - 1] # Get mean and standard deviations mean = _get_mean(self.kind, self.distance_type, imls, ctx, dists) return np.log(mean)
def test_retreival_tables_good_no_interp(self): """ Tests the retreival of the IML tables for 'good' conditions without applying magnitude interpolations """ gsim = GMPETable(gmpe_table=self.TABLE_FILE) # PGA np.testing.assert_array_almost_equal( _return_tables(gsim, 6.0, imt_module.PGA(), "IMLs"), np.array([2., 1., 0.5])) # PGV np.testing.assert_array_almost_equal( _return_tables(gsim, 6.0, imt_module.PGV(), "IMLs"), np.array([20., 10., 5.]), 5) # SA(1.0) np.testing.assert_array_almost_equal( _return_tables(gsim, 6.0, imt_module.SA(1.0), "IMLs"), np.array([2.0, 1., 0.5])) # Also for standard deviations np.testing.assert_array_almost_equal( _return_tables(gsim, 6.0, imt_module.PGA(), 0), 0.5 * np.ones(3)) np.testing.assert_array_almost_equal( _return_tables(gsim, 6.0, imt_module.SA(1.0), 0), 0.8 * np.ones(3))
def compute(self, ctx, imts, mean, sig, tau, phi): """ Returns the mean and standard deviations """ stds = [sig, tau, phi] stdis = [ const.StdDev.idx[sdt] for sdt in self.DEFINED_FOR_STANDARD_DEVIATION_TYPES ] for m, imt in enumerate(imts): # Return Distance Tables imls = _return_tables(self, ctx.mag, imt, "IMLs") # Get distance vector for the given magnitude idx = np.searchsorted(self.m_w, ctx.mag) dists = self.distances[:, 0, idx - 1] # Get mean and standard deviations mean[m] = np.log( _get_mean(self.kind, self.distance_type, imls, ctx, dists)) + site_term(self, ctx, dists, imt) stddevs = _get_stddevs(self, dists, ctx, imt, stdis) for s in stdis: stds[s][m] = stddevs[s]
def get_mean_and_stddevs(self, sites, rx, dists, imt, stddev_types): # List of GMPE weights, which is the product of the the branch weights # for the seed models vs the NGA East resampled models as well as the # weights for the indivudual GMPES as defined by Petersen et al. (2019) # # Note that the NGA East resampled models are a function of spectral # period. # # NGA East Seeds (1/3) # ├── B_bca10d (0.06633), wts = 0.333 * 0.06633 = 0.02208789 # ├── B_ab95 (0.02211), wts = 0.333 * 0.02211 = 0.00736263 # ... # NGA East Resampled or "USGS" (2/3) # ├── Model 1 (0.1009 for PGA), wts = 0.667 * 0.1009 = 0.0673003 # ├── Model 2 (0.1606 for PGA), wts = 0.667 * 0.1606 = 0.1071202 # ... # wts = [0] * len(self.gmpes) # Is IMT PGA or PGV? is_pga = imt == IMT.PGA() is_pgv = imt == IMT.PGV() # Is magnitude less than 4? If so, we will need to set it to 4.0 and # then extrapolate the tables at the end. # But... in the brave new world of new OpenQuake, sites, rx, and # dists are all exactly the same object, so when we copy rx to # rup, and change it, as well as when we change the distances # below, we need to do it all in rup, then pass rup as all three # contexts when we call the gmpe.get_mean_and_stddevs() rup = copy.deepcopy(rx) if rup.mag < 4.0: is_small_mag = True delta_mag = rup.mag - 4.0 rup.mag = 4.0 else: is_small_mag = False for i, tp in enumerate(self.ALL_TABLE_PATHS): if 'usgs' in tp: # Get model number from i-th path using regex mod_num = int(re.search(r'\d+', tp).group()) coefs = np.array(self.NGA_EAST_USGS.iloc[mod_num - 1]) # Is the IMT PGA, PGA, or SA? if is_pga: iweight = coefs[-2] elif is_pgv: iweight = coefs[-1] else: # For SA, need to interpolate; we'll use log-period and # linear-weight interpolation. iweight = np.interp( np.log(imt.period), np.log(self.per_array), coefs[self.per_idx_start:self.per_idx_end]) wts[i] = self.NGA_EAST_USGS_WEIGHT * iweight else: # Strip off the cruft to get the string we need to match str_match = tp.replace('nga_east_', '').replace('.hdf5', '') matched = self.NGA_EAST_SEEDS[self.NGA_EAST_SEEDS['model'] == str_match] if len(matched): iweight = self.NGA_EAST_SEEDS[self.NGA_EAST_SEEDS['model'] == str_match].iloc[0, 1] wts[i] = self.NGA_EAST_SEED_WEIGHT * iweight total_gmpe_weights = self.sigma_weights * wts if not np.allclose(np.sum(total_gmpe_weights), 1.0): raise ValueError('Weights must sum to 1.0.') mean = np.full_like(sites.vs30, 0) stddevs = [] for i in range(len(stddev_types)): stddevs.append(np.full_like(sites.vs30, 0)) # Apply max distance to dists.rrup -->> now rup.rrup np.clip(rup.rrup, 0, MAX_RRUP) # # Some models don't have PGV terms, so we will make PSA for them # and then use the conditional conversion to get PGV # if is_pgv: ab2020 = AbrahamsonBhasin2020(rup.mag) vimt = IMT.SA(ab2020.getTref()) # Loop over gmpes for i, gm in enumerate(self.gmpes): if is_pgv: # Is PGV and also not available for gm? try: _ = _return_tables(gm, rup.mag, imt, "IMLs") except KeyError: # # No table for PGV, compute vimt, then convert to PGV # vmean, vstddevs = gm.get_mean_and_stddevs( rup, rup, rup, vimt, stddev_types) tmean, tstddevs = ab2020.getPGVandSTDDEVS( vmean, vstddevs, stddev_types, rup.rrup, rup.vs30) except Exception: logging.error("Unexpected error:", sys.exc_info()[0]) else: # # Table exists for PGV, proceed normally # tmean, tstddevs = gm.get_mean_and_stddevs( rup, rup, rup, imt, stddev_types) else: tmean, tstddevs = gm.get_mean_and_stddevs( rup, rup, rup, imt, stddev_types) mean += tmean * total_gmpe_weights[i] for j, sd in enumerate(tstddevs): stddevs[j] += sd * total_gmpe_weights[i] # Zero out values at distances beyond the range for which NGA East # was defined. -->> was dists.rrup, now rup.rrup mean[rup.rrup > MAX_RRUP] = -999.0 # Do we need to extrapolate for small magnitude factor? if is_small_mag: if is_pga: slopes = np.interp(np.log(rup.rrup), np.log(self.SMALL_M_DIST), self.SMALL_M_SLOPE_PGA) elif is_pgv: slopes = np.interp(np.log(rup.rrup), np.log(self.SMALL_M_DIST), self.SMALL_M_SLOPE_PGV) else: interp_obj = RectBivariateSpline(np.log(self.SMALL_M_DIST), np.log(self.SMALL_M_PER), self.SMALL_M_SLOPE, kx=1, ky=1) slopes = interp_obj.ev(np.log(rup.rrup), np.log(imt.period)) mean = mean + slopes * delta_mag return mean, stddevs