def amplify_one(self, ampl_code, imt, poes): """ :param ampl_code: code for the amplification function :param imt: an intensity measure type :param poes: the original PoEs as an array of shape (I, G) :returns: the amplified PoEs as an array of shape (A, G) """ if isinstance(poes, list): # in the tests poes = numpy.array(poes).reshape(-1, 1) # Manage the case of a site collection with empty ampcode if ampl_code == b'' and len(self.ampcodes) == 1: ampl_code = self.ampcodes[0] ialphas = self.ialphas[ampl_code, imt] isigmas = self.isigmas[ampl_code, imt] A, G = len(self.amplevels), poes.shape[1] ampl_poes = numpy.zeros((A, G)) # Amplify, for each site i.e. distance for g in range(G): # Compute the probability of occurrence of GM within a number of # intervals p_occ = -numpy.diff(poes[:, g]) for mid, p, a, s in zip(self.midlevels, p_occ, ialphas, isigmas): # # This computes the conditional probabilities of exceeding # defined values of shaking on soil given a value of shaking # on rock. 'mid' is the value of ground motion on rock to # which we associate the probability of occurrence 'p'. 'a' # is the median amplification factor and 's' is the standard # deviation of the logarithm of amplification. # # In the case of an amplification function without uncertainty # (i.e. sigma is zero) this will return values corresponding # to 'p' times 1 (if the value of shaking on rock will be # larger than the value of shaking on soil) or 0 (if the # value of shaking on rock will be smaller than the value of # shaking on soil) # logaf = numpy.log(self.amplevels / mid) ampl_poes[:, g] += (1.0 - norm_cdf(logaf, numpy.log(a), s)) * p return ampl_poes
def _get_poes_site(mean_std, loglevels, truncation_level, ampfun, mag, sitecode, rrup, squeeze=False): """ NOTE: this works for a single site :param mean_std: See :function:`openquake.hazardlib.gsim.base.get_poes` :param loglevels: Intensity measure level per intensity measure type. See :function:`openquake.hazardlib.gsim.base.get_poes` :param truncation_level: The level of truncation of the normal distribution of ground-motion on rock :param ampl: Site amplification function instance of :class:openquake.hazardlib.site_amplification.AmpFunction :param mag: The magnitude of the earthquake :param rrup: The rrup distances :param squeeze: A boolean. Should be True when ... """ # Mean and std of ground motion for the IMTs considered in this analysis # N - Number of sites # L - Number of intensity measure levels # G - Number of GMMs mean, stddev = mean_std # shape (N, M, G) N, L, G = len(mean), len(loglevels.array), mean.shape[-1] assert N == 1, N M = len(loglevels) L1 = L // M # This is the array where we store the output results i.e. poes on soil out_s = numpy.zeros((N, L) if squeeze else (N, L, G)) # `nsamp` is the number of IMLs per IMT used to compute the hazard on rock # while 'L' is total number of ground-motion values nsamp = 40 # Compute the probability of exceedance for each in intensity # measure type IMT sigma = ampfun.get_max_sigma() for m, imt in enumerate(loglevels): # Get the values of ground-motion used to compute the probability of # exceedance on soil. soillevels = loglevels[imt] # Here we set automatically the IMLs that will be used to compute # the probability of occurrence of GM on rock within discrete # intervals ll = numpy.linspace(min(soillevels) - sigma * 4., max(soillevels) + sigma * 4., num=nsamp) # Calculate for each ground motion interval the probability # of occurrence on rock for all the sites for iml_l, iml_u in zip(ll[:-1], ll[1:]): # Set the arguments of the truncated normal distribution # function if truncation_level == 0: out_l = iml_l <= mean[:, m] out_u = iml_u <= mean[:, m] else: out_l = (iml_l - mean[:, m]) / stddev[:, m] out_u = (iml_u - mean[:, m]) / stddev[:, m] # Probability of occurrence on rock - The shape of this array # is: number of sites x number of IMLs x GMMs. This corresponds # to 1 x 1 x number of GMMs pocc_rock = (_truncnorm_sf(truncation_level, out_l) - _truncnorm_sf(truncation_level, out_u)) # Skipping cases where the pocc on rock is negligible if numpy.all(pocc_rock < 1e-10): continue # Ground-motion value in the middle of each interval iml_mid = numpy.log((numpy.exp(iml_l) + numpy.exp(iml_u)) / 2.) # Get mean and std of the amplification function for this # magnitude, distance and IML median_af, std_af = ampfun.get_mean_std( sitecode, imt, numpy.exp(iml_mid), mag, rrup) # Computing the probability of exceedance of the levels of # ground-motion loglevels on soil logaf = numpy.log(numpy.exp(soillevels) / numpy.exp(iml_mid)) tmp = 1. - norm_cdf(logaf, numpy.log(median_af), std_af) poex_af = numpy.reshape(numpy.tile(tmp, N), (-1, len(logaf))) # The probability of occurrence on rock has shape: # 1 x 1 x number of GMMs poex = poex_af.T * pocc_rock # Updating output out_s[:, m * L1: (m + 1) * L1, :] += poex return out_s
def amplify_one(self, ampl_code, imt, poes): """ :param ampl_code: code for the amplification function :param imt: an intensity measure type :param poes: the original PoEs as an array of shape (I, G) :returns: the amplified PoEs as an array of shape (A, G) """ if isinstance(poes, list): # in the tests poes = numpy.array(poes).reshape(-1, 1) # Manage the case of a site collection with empty ampcode if ampl_code == b'' and len(self.ampcodes) == 1: ampl_code = self.ampcodes[0] min_gm = numpy.amin(self.imtls[imt]) max_gm = numpy.amax(self.imtls[imt]) min_ratio = numpy.amin( numpy.array(self.amplevels[1:]) / numpy.array(self.amplevels[:-1])) * 0.9 min_ratio = min(max(min_ratio, 1.05), 1.1) allimls = [min_gm] while allimls[-1] < max_gm: allimls.append(allimls[-1] * min_ratio) allimls = numpy.array(allimls) A, G = len(self.amplevels), poes.shape[1] ampl_poes = numpy.zeros((A, G)) # Amplify, for each site i.e. distance for g in range(G): # Compute the probability of occurrence of GM within a number of # intervals by interpolating the hazard curve idx = numpy.nonzero(poes[:, g].flatten() > 1e-100) simls = allimls[allimls <= numpy.amax(self.imtls[imt][idx])] ipoes = numpy.interp(numpy.log10(simls), numpy.log10(self.imtls[imt][idx]), numpy.log10(poes[:, g].flatten()[idx])) ipoes = 10.0**ipoes p_occ = -numpy.diff(ipoes) # Calculate the amplification factor and sigma for the selected # IMLs self.levels = simls self._set_alpha_sigma(mag=None, dst=None) ialphas = self.ialphas[ampl_code, imt] isigmas = self.isigmas[ampl_code, imt] for mid, p, a, s in zip(self.midlevels, p_occ, ialphas, isigmas): # # This computes the conditional probabilities of exceeding # defined values of shaking on soil given a value of shaking # on rock. 'mid' is the value of ground motion on rock to # which we associate the probability of occurrence 'p'. 'a' # is the median amplification factor and 's' is the standard # deviation of the logarithm of amplification. # # In the case of an amplification function without uncertainty # (i.e. sigma is zero) this will return values corresponding # to 'p' times 1 (if the value of shaking on rock will be # larger than the value of shaking on soil) or 0 (if the # value of shaking on rock will be smaller than the value of # shaking on soil) # logaf = numpy.log(self.amplevels / mid) ampl_poes[:, g] += (1.0 - norm_cdf(logaf, numpy.log(a), s)) * p return ampl_poes