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
Exemple #2
0
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
Exemple #3
0
    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